Universidad Carlos III de Madrid

Ingeniería de Telecomunicación

Enero-Mayo 2010 / January-May 2010

Object-Orientation & Inheritance

Lab Section1.  Session 6 (lab): Object-Orientation & Inheritance (III)

Exercise Section1.1. Points and Figures (II)

The main objective of this exercise is to review the use of inheritance in Java and its application to arrays of objects. Inheritance is based on the use of abstract and extends reserved identifiers. We will write a generic class and several specific subclasses that derive from the first. All abstract methods will be implemented and other methods will be overridden to show the use of polymorphism when working with objects from a class hierarchy. Finally, we will use an array of objects from the previous hierarchy that will allow us to practice with all inheritance concepts.

In this exercise, we will calculate the total area of a collection of figures that have been previously created. Starting from the class Triangle, we will create a generic Figure class that will allow us to make abstraction when working with any type of figures. Once the behaviour of the Figure class has been defined, we will derive our Triangle class from it and then we will adapt it in order that it can be considered as a Figure. We will also create the Square class that will inherit also from Figure.

WARNING: the geometry of triangles and squares is a bit more complex to model of what may seem at a first look. If we try to solve them, you will loose most of the time dealing with such geometry problems, instead of the programming. Therefore, we are going to make two simplifications: one of them abou the area of the triangle and the other one about the shape of the squere. That is, this exercise is mathematically incorrect. Both simplifications will be explained in the corresponding section, but notice that in a real program, instead of an exercise like this one, you would need to use the right mathematics.

Once all figures are created, we will implement a class that contains an array of figures (for example, a triangle and a square) and then we will calculate the total area of them using class polymorphism to calculate the specific area of each one of them.

Inheritance. The Figure and Triangle classes

The Figure class represents a generic figure that will materialize later on a specific one (Triangle, Square, etc...). In Java, all this concept is represented by abstract classes that must be declared with the abstract reserved keyword.

Note

An abstract class is a class that declares one or more abstract methods whose implementation is done in the corresponding subclasses. Review the theory if you don't remember this concept.

The first task of the exercise is to define the following Figure abstract class which represents a generic geometric figure:

public abstract class Figure {
    
    /** Name of the figure */
    String name;
    
    /** Constructor of the figure with a name */
    public Figure(String name) {
    }
    
    /** Calculates the area of a figure */
    abstract public double area();
    
    /** Indicates if the figure is regular or not */
    abstract public boolean isRegular();
    
}

Start by downloading the following code Figure.java.

Note

Notice that two methods have been declared as abstract, therefore they must be implemented in the corresponding subclasses.

Constructors of the Figure class.
  1. Write the constructor of the class.

    Question

    Does it make sense to implement the constructor of an abstract class? What for?

The subclass Triangle.

The Triangle class now inherits from Figure and you must modify it so that it reflects such changes. To do so, start downloading the code listing of the Triangle class from this link Triangle.java and make the following changes:

Note

You will need to access the code of the Point class to be able to compile the Triangle class. You can download it from the following link Point.java.

  1. Declare the Triangle class as follows:

     public class Triangle extends Figure
  2. Modify all constructors so that, at the first line of the code, all of them invoke to the base class constructor of the Figure class. This is made by using the reference super.

  3. Implement the following methods:

    • The area() method that calculates the area of the triangle. The prototype of the method is as follows:

      public double area() {
      /* complete */
      }

      The triangle's area is calculated according to the following formula:

      Area = ( base X height ) / 2

      Hint 1

      Use the distance(Point anotherPoint) method, of the Point class, with the vertexes of the triangle.

      Hint 2

      To calculate the height of any triangle it is necessary to apply some trigonometry: assume that the triangle is isosceles or equilateral and suppose that the projection of the opposite vertex is on the middle point of the base.

    • The isRegular() method that allows to know whether a triangle is regular or not. The prototype of the method is as follows:

      public boolean isRegular() {
      /* complete */
      }

      The method must return true if the length of all sides of the triangle are equal.

      Hint

      You need only to compare the length of the three sides of the triangle.

    • The toString() method that allows to obtain a text string representation of the object. The prototype of the method is as follows:

      public String toString() {
      /* complete */
      }

      The method must return a string of characters with the values of the triangle according to some format. The output format of the text string is shown below (data values shown are only examples) :

      TRIANGLE [NAME=triangle1] [NON REGULAR] : VERTEXES (1.0, 1.0),(3.0, 1.0),(2.0, 2.0)

      Please, remember that what has been shown above is a formatted text string with example values for attributes. They are only used to show you how the output format is, so in the implementation of the method you must not use these values, instead of you have to work with attributes directly.

      Hint 1

      Use the toString() method of the vertexes of the triangle.

      Hint 2

      Remember that "+" operator, applied to text strings, allows to concatenate them.

The main method of the Triangle class

Now you must create a method to test the previous code. Create a main method in the Triangle class that carries out the following tasks:

  1. Create three points.

  2. Create a triangle from those previous points.

  3. Display on the console a descriptive text string with the values of the triangle.

  4. Finally, print the value of the triangle's area.

Inheritance. The Square class.

The Square class inherits also from Figure and has the following implementation:

public class Square extends Figure {

    /** Square vertexes */
    private Point vertex1;
    private Point vertex2;
    private Point vertex3;
    private Point vertex4;
      
    /** Constructor with name and vertexes */
    public Square(String name, Point diagonalVertex1, Point diagonalVertex3) {
    }

    /** Private method to calculate the vertexes for the other diagonal*/
    private void otherDiagonal(Point vertex1, Point vertex3) {
    }
    
    /** Method implementation to calculate the area */  
    public double area() {
      return 0;
    }
  
    /** Implementation of the abstract method to calculate if the figure is regular. */
    public boolean isRegular() {
      return false;
    }
  
    /** Returns a representative string of the square. */
    public String toString() {
      return null;
    }
}

Note 1

Notice that a square can be created from one of its diagonals, therefore, the constructor receives both vertexes of the diagonal as input parameters. To calculate the other two remaining vertexes, you have to implement another private method called otherDiagonal(Point vertex1, Point vertex3) that calculates and creates the other two vertexes of the second square's diagonal from those you have passed as parameters to the method, that is, it must calculate and create both vertexes vertex2 and vertex4 of the square.

Note 2

Also notice that, as it derives from the Figure abstract class, the Square class is forced to implement ALL abstract methods from Figure... Which are those?

Constructors of the Square class.

Download the skeleton of the Square class from this link Square.java and carry out the following tasks to implement the constructor of the class.

  1. Firstly, implement the following private method that allows to create the vertexes of the second diagonal from the two vertexes of the first diagonal. The prototype of the method is as follows:

    private void otherDiagonal(Point vertex1, Point vertex3) {
    /* complete */
    }

    This method creates both two vertexes of the second square's diagonal (vertex2 and vertex4) on the basis of the coordinates of the vertexes of the first diagonal that are passed as input parameters.

    Hint

    This is one of the proposed simplifications. For a correct solution, you would need to find the vector which is perpendicular to the defined diagonal, and then find the point to the appropiate distance. However, in order to avoid you wasting the time dealing with mathmatics, we propose you to make the following simplification: just suppose that the sides are parallel to the axis, and therefore x and y f the new vertexes are just those of the provided vertexes, but with x and y interexchanged.

  2. Implement the constructor of the class.

    Hint

    Use the method that you have implemented before to calculate the square's vertexes.

Auxiliary methods of the Square class.

Implement the methods of the Square class that are specified next:

  1. Write the area() method that allows to calculate the area of a square. The prototype of the method is as follows:

    public double area() {
    /* complete */
    }

    The method calculates the area of a square according to the following formula: Area = base X altura

    Hint

    Use the distance(Point anotherPoint) method of the Point class with the vertexes of the square.

  2. Write the isRegular() method that allows to calculate whether a square is a regular figure or not. The prototype of the method is as follows:

    public boolean isRegular() {
    /* complete */
    }

    This method is obvious.

  3. Write the toString() method that allows to obtain a text representation of the object. The prototype of the method is as follows:

    public String toString() {
    /* complete */
    }

    The method must return a string of characters with the values of the square according to some kind of format. In this case, the output format of the text string is shown below (data values shown are only examples) :

    SQUARE [NAME=square1] : VERTEXES (3.0, 3.0),(5.0, 3.0),(5.0, 5.0),(3.0, 5.0)

    Hint 1

    You can reuse most of the code of the toString() method of the triangle.

    Hint 2

    Remember that "+" operator, applied to text strings, allows to concatenate them.

The main method of the Square class

Now you must create a method to test all the previous code. Create the main method in the Square class that must do the next tasks:

  1. Create two points that will be the diagonal of your figure.

  2. Create a square from those previous points.

  3. Display on the console a descriptive text string with the values of the square.

  4. Finally, print the value of the square's area.

Arrays and polymorphism. Calculation of the area of several figures.

The FiguresArea class, which contains an array of figures, is the one that will allows us to calculate the total area of a collection of figures. It has the following definition:

public class FiguresArea {
    
    /** The array of figures */
    private Figure figures[] = null;
    
    /**  Constructor of the class with a fixed number of figures. */
    public FiguresArea(int figuresNumber) {
    }
    
    /** Calculates the total area of the array figures. */
    public double totalArea() {
	return 0.0;
    }
    
    /** Adds a new figure in the first empty position of the figures array. */
    public void addFigure (Figure f){
    }
    
    /** Prints a list with the array figures. */
    public void print() {
    }
    
    /** Main Program */
    public static void main(String args[]) throws Exception {
    }    
}

The constructor of the class initialises the array with the maximum number of figures. The addFigure() method allows to add an object of the Figure class at the first free position of the array. The totalArea() method will add the respective areas of the figures that are contained in the array and will return the total sum of them. The print() method must print that total area and a descriptive message for every figure on the console.

Constructor.

Download the FiguresArea class from the following link FiguresArea.java and carry out the following task:

  1. Implement the constructor of the class that initialises the array of figures with the maximum number of them.

Auxiliary methods of the FiguresArea class.

Implement the methods of the FiguresArea class that are specified next:

  1. Write the addFigure (Figure f) method that allows to add an object Figure to the array. The prototype of the method is as follows:

     public void addFigure (Figure f) {
     /* complete */
     }

    The method must add a new object Figure to the figure's array.

    Remember

    According to the theory, Figure is abstract and, therefore there could not exist any object instances from that class. Object instances are, in fact, from the subclasses of Figure, that is: Triangle, Square.

  2. Write the totalArea() method that allows to calculate the total area of the figures of the array.The prototype of the method is as follows:

    public double totalArea() {
    /* complete */
    }

    The method must calculate the total area of the figures that are contained in the array of figures. To do so, it traverses the array adding the corresponding area of each figure of the array.

    Hint

    Remember what it the purpose of abstract methods of the Figure class when implementing the method.

  3. Write the print() method that allows to print the total area of the figures. The prototype of the method is as follows:

    public void print() {
    /* complete */
    }

    The method prints on console the result of the calculation of the total area of the figures. Use the previous method to achieve it.

    Note

    You can print also what figure is and to do so, use the toString() method of each figure.

    Remember

    Polymorphism is a consequence of applying inheritance to classes and it allows what is known as method overriding by which, the same method can be implemented either at the base class or the subclass. At runtime, depending on the type of the object (which class the object actually instantiates), Java's interpreter will invoke to the one of the correspondig class.

The main method of the FiguresArea class

Create the main program that has to carry out the following tasks:

  1. Create an object of the FiguresArea class with two figures as maximum.

  2. Create a figure of the Triangle class. To do so, you will have to create previously the 3 points that constitute the vertexes of the triangle and then pass them to the constructor of Triangle.

  3. Create a figure of the Square class. To do so, you will have to create previously the 2 points that constitute diagonal of the square and then pass them to the constructor of Square.

  4. Add the triangle and the square to the array of figures of the FiguresArea class. Use the method you have implemented previously to do it.

  5. Print the result of the calculation of the total area of the figures. To do so, invoke to the corresponding method of the class.

Solutions

The solutions of this exercise are included in the following listings:

import java.io.BufferedReader;
import java.io.InputStreamReader;

/*
 * Figure.java
 *
 * (c) DIT-UC3M 2008
 *
 */

public abstract class Figure {

  /** Name of the figure */
  String name;

  /** Constructor of the figure with a name */
  public Figure(String name) {
    this.name = name;
  }

  /** Calculates the area of a figure */
  abstract public double area();

  /** Indicates if the figure is regular or not */
  abstract public boolean isRegular();

}

	  
// Point class
// (c) 2008 IT

public class Point {
  private double x;
  private double y;

  // Constructor
  public Point(double x, double y) {
    this.x = x;
    this.y = y;
  }

  /**
   * Returns the coordinates of the point in a string
   */
  public String toString() {
    // '+' operator in String objects does not mean mathematical sum, but
    // concatenation of strings
    return "(" + x + ", " + y + ")";
  }

  /**
   * Returns the distance to the origin It can be also calculated calling to
   * distance(new Point(0,0))
   */
  public double distanceToOrigin() {
    return Math.sqrt(x * x + y * y);
  }

  /* Getter methods */
  public double getX() {
    return x;
  }

  public double getY() {
    return y;
  }

  /** Returns the distance to another point */
  public double distance(Point anotherPoint) {
    double x1;
    double y1;

    x1 = x - anotherPoint.getX();
    y1 = y - anotherPoint.getY();
    return Math.sqrt(x1 * x1 + y1 * y1);
  }

  /** Returns the quadrant */
  public int quadrant() {
    if (x > 0.0 && y > 0.0) {
      return 1;
    } else if (x < 0.0 && y > 0.0) {
      return 2;
    } else if (x < 0.0 && y < 0.0) {
      return 3;
    } else if (x > 0.0 && y < 0.0) {
      return 4;
    } else {
      // (x==0.0 || y==0.0)
      return 0;
    }
  }

  /**
   * Returns the nearest point of the array in the parameter or null if array is
   * empty
   * 
   * @param otherPoints
   * @return
   */
  public Point nearest(Point[] otherPoints) {
    Point nearestPoint = null;
    double minDistance;
    double distance;

    if (otherPoints != null && otherPoints.length > 0) {
      // Start storing the first point in the array as the nearest one
      minDistance = distance(otherPoints[0]);
      nearestPoint = otherPoints[0];

      for (int i = 1; i < otherPoints.length; i++) {
        // If nearer point is found, this is the new nearest one
        distance = distance(otherPoints[i]);
        if (distance < minDistance) {
          distance = minDistance;
          nearestPoint = otherPoints[i];
        }
      }
    }

    return nearestPoint;
  }
}

	  
/**
 * Triangle.java
 * 
 * (c) DIT-UC3M 2008
 * 
 */

public class Triangle extends Figure {

  /** Vertexes of the triangle */
  private Point vertex1;
  private Point vertex2;
  private Point vertex3;

  /** Constructor of a triangle with their vertexes */
  public Triangle(String name, Point vertex1, Point vertex2, Point vertex3) {
    super(name);
    this.vertex1 = vertex1;
    this.vertex2 = vertex2;
    this.vertex3 = vertex3;

  }

  /** Returns an array with the lenght of every edge of the triangle */
  public double[] edgesLength() {
    double edgesLength[] = new double[3];

    // Length 1->2
    edgesLength[0] = vertex1.distance(vertex2);
    // Length 2->3
    edgesLength[1] = vertex2.distance(vertex3);
    // Length 3->1
    edgesLength[2] = vertex3.distance(vertex1);

    return edgesLength;
  }

  /** Implementation of the abstract method to calculate the triangle area. */
  public double area() {
    // The area is ( base x height ) / 2
    // We have to calculate the medium point from the base
    // to calculate the height
    // WARNNING: this an aproximation, the correct mathematical are as a bit
    // more complex.
    Point medium = new Point((vertex1.getX() + vertex2.getX()) / 2,
        (vertex1.getY() + vertex2.getY()) / 2);
    double base = vertex1.distance(vertex2);
    double height = medium.distance(vertex3);
    return (base * height) / 2;
  }

  /**
   * Implementation of the abstract method to indicate if the triangle is
   * regular.
   */
  public boolean isRegular() {
    double edgesLength[] = edgesLength();
    if (edgesLength[0] == edgesLength[1] && edgesLength[1] == edgesLength[2]
        && edgesLength[2] == edgesLength[0]) {
      return true;
    }
    return false;
  }

  /** Returns a representative string of the triangle. */
  public String toString() {
    String s = "TRIANGLE";
    s += " [NAME=" + name + "]";
    if (isRegular()) {
      s += " [REGULAR] ";
    } else {
      s += " [IRREGULAR] ";
    }
    s += " : " + "VERTEXES " + vertex1.toString() + "," + vertex2.toString()
        + "," + vertex3.toString();
    return s;
  }

  public static void main(String[] args) {
    Point p1 = new Point(1, 1);
    Point p2 = new Point(3, 1);
    Point p3 = new Point(2, 3);
    Triangle t = new Triangle("Triangle1", p1, p2, p3);
    System.out.println(t.toString());
    System.out.println("Area: " + t.area());
  }
}

	  
/*
 * Square.java
 *
 * (c) DIT-UC3M 2008
 *
 */

public class Square extends Figure {

  /** Square vertexes */
  private Point vertex1;
  private Point vertex2;
  private Point vertex3;
  private Point vertex4;

  /** Constructor with name and vertexes */
  public Square(String name, Point diagonalVertex1, Point diagonalVertex3) {
    super(name);
    this.vertex1 = diagonalVertex1;
    this.vertex3 = diagonalVertex3;
    otherDiagonal(diagonalVertex1, diagonalVertex3);
  }

  /** Private method to calculate the vertexes for the other diagonal */
  private void otherDiagonal(Point vertex1, Point vertex3) {
    vertex2 = new Point(vertex3.getX(), vertex1.getY());
    vertex4 = new Point(vertex1.getX(), vertex3.getY());
  }

  /** Method implementation to calculate the area */
  public double area() {
    // In a square, the area is the base multiplied by the height
    double base = vertex1.distance(vertex2);
    double height = vertex1.distance(vertex4);
    return base * height;
  }

  /**
   * Implementation of the abstract method to calculate if the figure is
   * regular.
   */
  public boolean isRegular() {
    // Due to our simplification, the square may not be actually a square, but a
    // rectangle. However, that is just our simplification, so we will return
    // always true: a square is always regular, by definition
    return true;
  }

  /** Returns a representative string of the square. */
  public String toString() {
    String s = "SQUARE";
    s += " [NAME=" + name + "]";
    s += " : " + "VERTEXES " + vertex1.toString() + "," + vertex2.toString()
        + "," + vertex3.toString() + "," + vertex4.toString();
    return s;
  }

  public static void main(String[] args) {
    Point p1 = new Point(1, 3);
    Point p2 = new Point(3, 1);
    Square s = new Square("Square1", p1, p2);
    System.out.println(s.toString());
    System.out.println("Area: " + s.area());
  }

}

	  
import java.io.BufferedReader;
import java.io.InputStreamReader;

/*
 * FiguresArea.java
 *
 *
 * (c) DIT-UC3M 2008
 *
 */

public class FiguresArea {

  /** The array of figures */
  private Figure figures[] = null;

  /** Constructor of the class with a fixed number of figures. */
  public FiguresArea(int figuresNumber) {
    figures = new Figure[figuresNumber];
  }

  /** Calculates the total area of the array figures. */
  public double totalArea() {
    double totalArea = 0;
    for (int i = 0; i < figures.length; i++) {
      System.out.println(" Summing area of figure " + i + ":"
          + figures[i].area());
      totalArea += figures[i].area();
    }
    return totalArea;
  }

  /** Adds a new figure in the first empty position of the figures array. */
  public void addFigure(Figure f) {
    for (int i = 0; i < figures.length; i++) {
      if (figures[i] == null) {
        figures[i] = f;
        break;
      }
    }
  }

  /** Prints a list with the array figures. */
  public void print() {
    for (int i = 0; i < figures.length; i++) { 
	/* 
	 * The call to the toString method works because 
	 * this method is defined in the Object class 
	 * (which all Java classes extend).
	 * In general, we need to declare the method in the parent class
	 * in order to be able to call it applying polymorphism.
	 */
	System.out.println(figures[i].toString());
    }
    System.out.println("Total area: "+totalArea());
  }

  /** Main Program */
  public static void main(String args[]) throws Exception {
    FiguresArea figuresArea = new FiguresArea(2);

    Point p1 = new Point(1, 1);
    Point p2 = new Point(3, 1);
    Point p3 = new Point(2, 3);
    Triangle t = new Triangle("Triangle1", p1, p2, p3);

    Point p4 = new Point(1, 3);
    Point p5 = new Point(3, 1);
    Square s = new Square("Square1", p4, p5);

    figuresArea.addFigure(t);
    figuresArea.addFigure(s);
    
    figuresArea.print();
  }
}

	  

Homework Section2.  Homework

Exercise Section2.1.  Inheritance and references to the base class

Objective

The resolution of this exercise expects that the student learns the basics of references to a base class in inheritance hierarchies.

Exercise

Download the following code listings ( Position.java, Figure.java, Castle.java, Queen.java ) and analyse both the class hierarchy and the Position class that is going to be used.

We are going to deal with a set of figure elements. As Figure class is abstract, we can't create instances from it, therefore, the collection of elements will be made up of objects from the Castle and Queen classes, indistinctly.

Implement the necessary code to hold, in the same collection and indistinctly, 2 objects of Queen class and 4 objects of Castle class.

Once the previous code has been implemented, traverse the collection invoking public void whoAmI() method to test the correct operation of the base class references.

Solution

The solution is included in the following listing:

/** Testing class */
public class MainEn {
  public static int MAX_FIGURES = 6;

  // Testing method
  public static void main(String args[]) {
    Figure figures[] = new Figure[MAX_FIGURES];

    // Objects are created
    figures[0] = new Queen(Figure.WHITE);
    figures[1] = new Castle(Figure.WHITE);
    figures[2] = new Castle(Figure.WHITE);
    figures[3] = new Queen(Figure.BLACK);
    figures[4] = new Castle(Figure.BLACK);
    figures[5] = new Castle(Figure.BLACK);

    // Go through the array with the use of references
    // to base class and polymorphism
    for (int i = 0; i < MAX_FIGURES; i++) {
      figures[i].whoAmI();
    }
  }
} // Main

	  

Further questions

Once this exercise has been finished, answer the following questions:

  • Which methods can be really invoked on the collection elements?

  • If Castle class has implemented void castle() method ("enrocar" in Spanish), could it be possible to invoke that method from a reference to the base class?

  • What should we have to do in order to be able to use the previous void castle() method from an object of Castle class that is pointed by a reference to Figure class?

  • What should we do to know exactly to which class belongs every object pointed by a reference to the base class?

Exercise Section2.2. Exercise to practice with Figures

In this exercise we are going to review the main concepts of Object Oriented Programming (OOP) in Java with an application to create a class hierarchy to define geometric figures.

IMPORTANT NOTE: Remember that it is essential that you test your code whenever you implement any method, even though you are not asked to do so explicitly.

The Figure interface.

In Java, an interface represents a kind of specification for all classes that implement it. Is is normally used to define a set of methods that we want to be provided by those classes.

For example, the Comparable interface represents objects that can be compared among them. It defines the compareTo() method that allows to compare two objects. Every class whose objects want to be compared, as stated before, must implement this method. With an interface, further design and reuse of code is easily made since all objects share the same comparison method and the result of it.

Before going on to the next sections, try to answer the following questions:

  • What is an interface?

  • How is it implemented in Java?

  • What does it mean when a class implements an interface. How do you write this in Java?

All classes that are defined in this exercise must provide a basic set of methods, such as calculating the area of a geometric figure. In Java, this is achieved by defining the interface that declares all methods that must be implemented by the classes that implement it. For this exercise, every class that is created must implement the Figure interface.

The geometric figure.

An abstract class is a class that can not be instantiated. This is shown by the use of the abstract keyword in its declaration. An abstract class has "at least" one abstract method. That is, a method which is only declared but not implemented. This abstract method should be implemented by any subclass of the class. There is no point in instantiating objects of an abstract class and only subclasses of it can instantiate objects.

Remember that an abstract class can have constructors, though objects from it can not be instantiated.

  1. Write the code of the GeometricFigure abstract class, which must store the common information for all geometric figures (for example, a descriptive label) and has to provide all methods that can be shared among figures and are independent from the concrete shape of them. This class must implement the Figure interface. Every class that can be represented by a geometric figure will inherit from GeometricFigure class.

    Every figure will have a descriptive label, so you should define an attribute of type String to hold the text of the label.

  2. Write a constructor that receives as input parameter the descriptive label of the figure.

  3. Write the get and set methods that allow to modify the text label's attribute. As these methods should not be modified by anybody, declare them as final to avoid any subclass to change the code of them (method overriding).

  4. Implement the printDescription() method. Notice that is not an abstract method although it invokes other abstract methods. Also, to avoid subclasses to change the code of it (method overriding), declare it as final.

    The method must print a text description of the figure on the console, including the label's text, the type of figure and its area, with the following format:

    Tag: C-5
    Figure Type: Square
    Area: 25

    Remember that this class must implement the Figure interface, so it must provide the code for the complete set of methods that have been defined in such interface. These methods should be implemented with the available information in the class, that is: getTag and printDescription methods. It is not necessary to include those methods which are impossible to be programmed in the class (Java assumes that they are implicitly abstract), but subclasses are responsible to provide their code implementations.

The rectangle.

The next class to implement represents a rectangle and, obviously, its name will be Rectangle. This class inherits from GeometricFigure and implements the Figure interface. A rectangle is defined by two dimensions, the base and the height and both are assumed to be integer values.

  1. Write the class declaration and its correspondings attributes.

  2. Write the constructor and the basic accesor get and set methods.

  3. Write the following methods of the class:

    public String getFigureType();
    
    public double area();
    
    public void drawTxt();

    The drawTxt() method must print the figure on the console. For example, a rectangle of base 6 and height 3 can be printed as follows:

    ******
    ******
    ******
    
  4. Download the following code FiguresTesting and implement the code of the main method to create, first, an instance of Rectangle class and then print it on the console along with its description.

  5. Answer the following questions:

    • Show the difference between a class and an object.

    • Which steps are involved in the instantiation's process of an object?

    • How is an object instantiated in Java?

REMEMBER: If a class implements an interface, automatically, all subclasses of it also implement that interface, even though this is not explicitly mentioned in its declaration. Notice that Rectangle implements the Figure interface though you haven't mentioned it in its declaration. That is because Rectangle inherits from a class that implements Figure.

The square.

A square is a type of rectangle where both base and height are equals. In Java, we can easily create a Square class by deriving it from Rectangle class.

  1. Write the Square class so that it inherits from the Rectangle class of the previous section. Square class just only needs a constructor which receives a single input parameter: the side value. The constructor will invoke the constructor of the Rectangle superclass with the same value for the parameters of base and height

  2. Test the new class by adding the necessary code to FiguresTesting class.

  3. Notice that, thanks to inheritance, it is possible to invoke methods of the Rectangle superclass on an object of a derived type Square without the need of programming them again.

  4. Answer the following questions:

    • What is inheritance?

    • How do you express in Java that one class inherits from another?

    • Which methods of the superclass are visible from the subclasses?

    • What is the meaning of method overriding?

    • Remember that, opposite to the rest of the methods of a class, subclasses don't automatically inherit constructors from the superclass, but they can be invoked by the use of super() keyword.

Reference to interfaces.

In this section, you must improve FiguresTesting class to provide a user interface in text mode that allows the user to choose the figure that he/she wants to print on the console, then asks for the correct parameters for each figure, creates an instance of the correct class and, finally, prints the figure description and the figure itself on the console.

Use the following menu:

1.- Create rectangle
2.- Create square
3.- Display figure
0.- Exit

If the user selects one of the 2 first options, the program must ask him/her for the correct data. If he/she selects option 3, the last figure will be printed on the console (including its description). The menu must be shown until the user select the option Exit.

To simplify the generation of the correct object from the data entered by the user, it would be useful to add a readFigureData() method to each class. This method would receive, as an input parameter, an object of type BufferedReader from which, it will read the data introduced by the user. Then, it would return a correct instantiated object of the class with the entered data. Declare it as a static method.

Answer the following questions:

  • Which type are both instantiated objects (in options 1 and 2)?

  • Which type is the variable that references them?

  • Which methods from superclass are visible from the subclass?

  • Can you use the same variable as a reference for diferent types of figures? Why?

Solutions

The solutions of this exercise are included in the following listings:

abstract class GeometricFigure implements Figure {

  private String tag;

  public GeometricFigure(String tag) {
    this.tag = tag;
  }

  public String getTag() {
    return tag;
  }

  public void setTag(String tag) {
    this.tag = tag;
  }

  abstract public String getFigureType();

  abstract public double area();

  abstract public void drawTxt();

  final public void printDescription() {
    System.out.println("Tag: " + getTag());
    System.out.println("Figure Type: " + getFigureType());
    System.out.println("Area: " + area());
    // drawTxt();
  }

}

	  
public interface Figure {

  public String getTag();

  public String getFigureType();

  public double area();

  public void drawTxt();

  public void printDescription();

}

	  
import java.io.*;

public class Rectangle extends GeometricFigure {

  private int base;
  private int height;

  public Rectangle(int base, int height) {
    this(base, height, "Rectangle");
  }

  public Rectangle(int base, int height, String tag) {
    super(tag);
    this.base = base;
    this.height = height;
  }

  public int getBase() {
    return base;
  }

  public void setBase(int base) {
    this.base = base;
  }

  public int getHeight() {
    return height;
  }

  public void setHeight(int height) {
    this.height = height;
  }

  public String getFigureType() {
    return "Rectangle";
  }

  public double area() {
    return (base * height);
  }

  public void drawTxt() {
    for (int row = 1; row <= height; row++) {
      // Print every row with *
      for (int col = 1; col <= base; col++) {
        System.out.print("*");
      }
      // change of line
      System.out.println();
    }

  }

  /**
   * Asks for the necessary data to define a rectangle and generates an object
   * with such data
   */
  public static Rectangle readFigureData(BufferedReader entry) {

    Rectangle r = null;
    int base, height;
    String tag;

    try {
      System.out.print("Enter the base: ");
      System.out.flush();
      base = Integer.parseInt(entry.readLine());

      System.out.print("Enter the height: ");
      System.out.flush();
      height = Integer.parseInt(entry.readLine());

      System.out.print("Enter tag: ");
      System.out.flush();
      tag = entry.readLine();

      r = new Rectangle(base, height, tag);
    } catch (IOException ioe) {
      // Error (in/out):
      // A message is shown and null is returned
      System.err.println("Input/Output errora");
    } catch (NumberFormatException nfe) {
      // Error (invalid data):
      // A message is shown and null is returned
      System.err.println("Invalid data error");
    }

    return r;

  }

}

	  
import java.io.*;

public class Square extends Rectangle {

  public Square(int edge) {
    this(edge, "Square");
  }

  public Square(int edge, String tag) {
    super(edge, edge, tag);
  }

  public String getFigureType() {
    return "Square";
  }

  /**
   * Asks for the necessary data to define a Square and generates an object with
   * such data
   */
  public static Square readFigureData(BufferedReader entry) {
    Square c = null;
    String tag;
    int edge;

    try {

      System.out.print("Enter the edge: ");
      System.out.flush();
      edge = Integer.parseInt(entry.readLine());

      System.out.print("Enter the tag: ");
      System.out.flush();
      tag = entry.readLine();

      c = new Square(edge, tag);

    } catch (IOException ioe) {
      // Error (in/out):
      // A message is shown and null is returned
      System.err.println("Input/Output error");

    } catch (NumberFormatException nfe) {
      // Error (invalid data):
      // A message is shown and null is returned
      System.err.println("Invalid data error");
    }

    return c;
  }

}

	  
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class FiguresTesting {

  /**
   * Basic testing: Generate and show figures
   * 
   * Example of tests to see the classes
   */
  private static void basicTesting() {

    Figure f;

    // Testing rectangle
    f = new Rectangle(10, 5);
    f.printDescription();
    f.drawTxt();

    System.out.println(); // To separate a figure from the other

    // testing Square
    f = new Square(4);
    f.printDescription();
    f.drawTxt();

    System.out.println();
  }

  private static void showMenu() {
    System.out.println();
    System.out.println("1. Create rectangle");
    System.out.println("2. Create square");
    System.out.println("3. See figure");
    System.out.println("0. Exit");
    System.out.print("Select an option > ");
  }

  public static void main(String args[]) {
    // Used for the first part of the test
    // basicTesting();

    Figure f = null;
    String sOption;
    int iOption = 0;

    BufferedReader entry = new BufferedReader(new InputStreamReader(System.in));

    // Program is executed till the user press 0-Exit"
    do {

      // Show the menu
      showMenu();

      // Read the user option
      try {
        sOption = entry.readLine();
        iOption = Integer.parseInt(sOption);
      } catch (IOException ioe) {
        // input/output error
        System.err.println("Input/Output error");
        iOption = 0; // Finish
      } catch (NumberFormatException nfe) {
        // Error: Wrong option
        iOption = -1;
      }

      switch (iOption) {

      case 0:
        // Nothing, do-loop ends
        break;

      case 1: // Rectangle
        f = Rectangle.readFigureData(entry);
        break;

      case 2: // Square
        f = Square.readFigureData(entry);
        break;

      case 3: // see figure
        if (f != null) {
          f.drawTxt();
          f.printDescription();
        } else {
          System.out.println("Error: you must select a figure first");
        }
        break;

      default: // error
        System.out.println("Wrong option");

      }

    } while (iOption != 0); // Repeats till user select option 0-exit

  }

}
	  

Exercise Section2.3.  Cypher

Objective

This exercise tries to get an overall view of how Object Oriented Programmig allows us to reuse code, as long as we use it correctly.

Exercise

Let's assume that we have a little knowledge about cypher theory with strings of characters. Let's say that we have heard of several cypher algorithms, most of them which are very difficult to implement. However, there is one called Caesar, which is based on character's rotation, that has a reasonable implementation.

Caesar's algorithm is based on the order of the alphabet characters. Each character of the input text string is replaced by an output character that is calculated by adding N positions to the letter on the alphabet. For example, if we find the 'A' character and the value of N is 3, the output character that will replace would be 'D'.

Implement an Object Oriented Programming solution that allows us to easily change this algorithm by another one which could be better in the future.

First of all, write a solution based on an abstract Cypher class that models a generic encryption algorithm, with the basic encrypt and decrypt operations (that, for instance, receive a String and return a String), and then a CaesarCypher class that inherits from the first one and implements the Cesar's algorithm.

Second, write a solution based on the definition of a Cryptable interface and a CaesarCypher class that implements it.

Solution

The solution using an abstract class (inheritance) is included in the following listing:

public abstract class Cypher {

  // Functions that define the encryption and decryption.
  abstract public String encrypt(String string);

  abstract public String decrypt(String string);

  /**
   * 
   * @param args
   *          [0] encrypt/decrypt
   * @param args
   *          [1] string to encrypt/decrypt
   */
  public static void main(String[] args) {
    if (args.length != 2) {
      System.out.println("Usage: java Cypher encrypt/decrypt [string]");
    } else {
      Cypher cc = new CaesarCypher();
      if (args[0].equals("encrypt")) {
        System.out.println(cc.encrypt(args[1]));
      } else if (args[0].equals("decrypt")) {
        System.out.println(cc.decrypt(args[1]));
      } else {
        System.out.println("Usage: java Cypher encrypt/decrypt [string]");
      }
    }
  } // main

} // Cypher

/**
 * Specific implementation for a cypher, which replace each plain-text letter
 * with a fixed number of places down the alphabet.
 * Simple version ignoring punctuation marks.
 */
class CaesarCypher extends Cypher {
  /** Number of places which are going to be used for the replacement */
  private static int CHARS_NUMBER_TO_SHIFT = 10;

  /**
   * Encrypts a string with the basic Caesar's cypher.
   * 
   * @param string
   *          String to encrypt
   * @return Encrypted String
   */
  public String encrypt(String string) {
      String encryptedString = "";
      for (int i = 0; i < string.length(); i++) {
	  char letter = string.charAt(i);
	  letter = (char) (letter + CHARS_NUMBER_TO_SHIFT);
	  if (letter > 'z') {
	      letter = (char) (letter - 'z' + 'a' -1);
	  }
	  
	  encryptedString += letter;
      }
      return encryptedString;
    
  } // encrypt

  /**
   * Decrypts a string with the basic Caesar's cypher.
   * 
   * @param string
   *          String to decrypt
   * @return Decrypted String
   */
   public String decrypt(String string) {
       String decryptedString = "";
       for (int i = 0; i < string.length(); i++) {
	   char letter = string.charAt(i);
	   letter = (char) (letter - CHARS_NUMBER_TO_SHIFT);
	   if (letter < 'a') {
	       letter = (char) (letter + 'z' - 'a' + 1);
	   }
	   
	   decryptedString += letter;
       }
       return decryptedString;
   } // decrypt
    

} // CaesarCypher
	  

The solution using the interface is included in the following listing:

public class Cypher {
  /**
   * 
   * @param args
   *          [0] encrypt/decrypt
   * @param args
   *          [1] string to encrypt/decrypt
   */
  public static void main(String[] args) {
    if (args.length != 2)
      System.out.println("Usage: java Cypher encrypt/decript [string]");
    else {
      Cryptable cc = new CaesarCypher();

      if (args[0].equals("encrypt")) {
        System.out.println(cc.encrypt(args[1]));
      } else if (args[0].equals("decrypt")) {
        System.out.println(cc.decrypt(args[1]));
      } else {
        System.out.println("Usage: java Cypher encrypt/decript [string]");
      }
    }
  } // main
} // Cifrado

// Set of methods that specify the possibility of encrypt and decrypt in the
// class that implements it.
interface Cryptable {
  public String encrypt(String string);

  public String decrypt(String string);
}

/**
 * Implementation for a cypher, which replace each plain-text letter with a
 * fixed number of places down the alphabet
 */
class CaesarCypher implements Cryptable {
  /** Number of places which are going to be used for the replacement */
  private static int CHARS_NUMBER_TO_SHIFT = 10;

  /**
   * Characters that can be used for the shift The characters ordering may be
   * changed in the array
   */
  private static char characters[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
      'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
      'w', 'x', 'y', 'z', '_', '-', '.', '#', '@', '&', '%', '/', '(', '(',
      '+', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', '0', '1',
      '2', '3', '4', '5', '6', '7', '8', '9', 'L', 'M', 'N', 'O', 'P', 'Q',
      'R', 'S', 'T', 'U', 'W', 'X', 'Y', 'Z' };

  /**
   * Given a character, this function returns its position in the array if it
   * exists, -1 otherwise
   * 
   * @param character
   * @return
   */
  private int searchCharPosition(char character) {
    int pos = -1;
    boolean found = false;

    int i = 0;
    while ((!found) && (i < characters.length)) {
      found = (characters[i] == character);
      i++;
    }
    if (found) {
      return (i - 1);
    } else {
      return pos;
    }
  } // searchCharPosition()

  /**
   * Replace the given character for the encryption.
   * 
   * @param character
   *          Char to replace
   * @return New (already replaced) character, which was CHARS_NUMBER_TO_SHIFT
   *         positions down the alphabet
   */
  private char encryptReplace(char character) {
    int pos = searchCharPosition(character);
    if (pos == -1) {
      return character;
    } else {
      int replacingCharPosition = 0;
      int newPosition = pos + CaesarCypher.CHARS_NUMBER_TO_SHIFT;
      if (newPosition <= characters.length - 1) {
        replacingCharPosition = newPosition;
      } else {
        replacingCharPosition = newPosition - characters.length;
      }

      return characters[replacingCharPosition];
    }

  } // encryptReplace()

  /**
   * Replace the given character for the decryption.
   * 
   * @param character
   *          Char to replace
   * @return New (already replaced) character, which was CHARS_NUMBER_TO_SHIFT
   *         positions up the alphabet
   */
  private char decryptReplace(char character) {
    int pos = searchCharPosition(character);
    if (pos == -1) {
      return character;
    } else {
      int replacingCharPosition = 0;
      int newPosition = pos - CaesarCypher.CHARS_NUMBER_TO_SHIFT;
      if (newPosition >= 0) {
        replacingCharPosition = newPosition;
      } else {
        replacingCharPosition = characters.length - Math.abs(newPosition);
      }
      return characters[replacingCharPosition];
    }
  } // decryptReplace()

  /**
   * Encrypts a string with the basic Caesar's cypher.
   * 
   * @param string
   *          String to encrypt
   * @return Encrypted String
   */
  public String encrypt(String string) {
    String encryptedString = "";
    for (int i = 0; i < string.length(); i++) {
      char letter = string.charAt(i);
      letter = encryptReplace(letter);
      encryptedString += letter;
    }
    return encryptedString;
  } // encrypt

  /**
   * Encrypts a string with the basic Caesar's cypher.
   * 
   * @param string
   *          String to decrypt
   * @return Decrypted String
   */
  public String decrypt(String string) {
    String decryptedString = "";
    for (int i = 0; i < string.length(); i++) {
      char letter = string.charAt(i);
      letter = decryptReplace(letter);
      decryptedString += letter;
    }
    return decryptedString;
  } // decrypt
} // CifradoCesar