Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inheritance concerns between Square/Rectangle (with constrained invariants) which share Quadrilateral base

I have an interface Polygon, and then I have a class Quadrilateral. Then, I have two classes, Square and Rectangle, which extends the Quadrilateral.

Quadrilateral consists of the instance variables sideA, sideB, sideC, and sideD. It contains the methods area() and perimeter() to compute the area and perimeter of any quadrilateral.

With that in mind, the class Square has one instance variable, lengthOfSides, and the class Rectangle has two instance variables, length and width.

Since the methods area and perimeter in Quadrilateral can be used for calculating the area and perimeter of any quadrilateral, including a square and rectangle, I thought it would be best to just construct a Square or Rectangle and then call the super class to assign the sides (needed in Quadrilateral for area and perimeter calculations). In addition, when the instance variables in Square or Rectangle are changed, the setters also update the associated values in the parent classes.

Here is the Square class:

/**
 * A model for a Square.
 * 
 * @author BTKS
 */
public class Square extends Quadrilateral {

    private static final double ANGLES_SUM = 180; // the total sum of two opposite angles in degrees

    private double lengthOfSides; // the length of each side

    /**
     * Construct a new Square.
     * 
     * @param lengthOfSides the length of each side
     */
    public Square(double lengthOfSides) {
        super(ANGLES_SUM, lengthOfSides, lengthOfSides, lengthOfSides, lengthOfSides);

        this.lengthOfSides = lengthOfSides;
    }

    /**
     * @return the length of each side
     */
    public double getLengthOfSides() {
        return lengthOfSides;
    }

    /**
     * @param lengthOfSides the length of each side
     */
    public void setLengthOfSides(double lengthOfSides) {
        this.lengthOfSides = lengthOfSides;

        super.setSideA(lengthOfSides);
        super.setSideB(lengthOfSides);
        super.setSideC(lengthOfSides);
        super.setSideD(lengthOfSides);
    }
}

Is this considered bad practice? This is for a college assignment, and she didn't specify what she was looking for. It seemed useless to extend the class Quadrilateral if I were to not use anything from Quadrilateral in Square.

like image 786
Brandon Smith Avatar asked Sep 13 '15 23:09

Brandon Smith


1 Answers

It depends on what you want the "inheritance" relationship to represent here. Often, what one wants to express is best NOT expressed using what is called "object-oriented inheritance" (indeed, I have found few uses for this kind of inheritance).

In this case, the inheritance relationship seems to express the fact that the subclass has "additional constraints" relative the superclass. If Polygon were a class in itself rather than an interface:

  • Polygon (anything goes, as long as it is convex)
  • Quadrilateral (additional constraint of having only 4 edges)
  • Rectangle (additional constraint of having Pi/2 angles)
  • Square (additional constraint of having identical edge lengths)

Basically, I would:

Either just program out the Quadrilateral, remove the setters and make all instance variables final. This gets rid of phenomena whereby you get uncontrolled changes in a Square if someone changes the sides individually. (Generally finals are a Good Idea). Subclasses then reduce to just having special constructors.

Or program out the Quadrilateral only, do not subclass, give it boolean checks: isRectangle(), isSquare(), and maybe leave the setters. But that sounds less elegant.

Also recommending Bertrand Meyer's "The many faces of inheritance: a taxonomy of taxonomy" (1996) if you can find it, it's paywalled but there is probably someone with IEEE Xplore access nearby.

like image 97
David Tonhofer Avatar answered Sep 29 '22 22:09

David Tonhofer