5

Possible Duplicate:
Is deriving square from rectangle a violation of Liskov's Substitution Principle?

By applying the LSP, can anyone give me an implementation of Square and Rectangle?

I have read the book - "Head First Object-Oriented Analysis and Design", they said if Sqaure inherit from Rectangle, it violated the LSP but does not have a proper implementation.

Anyone want a try?

Community
  • 1
  • 1
Howard
  • 19,215
  • 35
  • 112
  • 184
  • 1
    This is the canonical LSP example, the problem generally being that Rectangles have width and length, but squares only need a 'side': http://stackoverflow.com/questions/1030521/is-deriving-square-from-rectangle-a-violation-of-liskovs-substitution-principle – wkl Dec 03 '10 at 18:25
  • Or perhaps inherit from `Quadrilateral`, which in turn inherits from `Shape`. Quadrilaterals all have four sides, four angles, etc. – David R Tribble Dec 03 '10 at 18:28
  • @Loadmaster: Quadrilateral has the same problem. If I'm defining my Rectangle to let me mutate the width and height, then presumably my Quadrilateral class lets me reposition the four vertices. If I can do that, and if Rectangle and/or Square is a Quadrilateral then the vertex repositioning method will violate LSP. The fundamental issue is that the hierarchies that we learned in grade school geometry are based on the assumption that shapes are immutable. Stretching a Rectangle in mathematics doesn't change the rectangle -- it yields a new rectangle (often called the "image"). – Laurence Gonsalves Dec 03 '10 at 18:37
  • Ah, that problem... It has actually nothing to do with OO. The problem is related to mutability. If you do "OO over immutable objects" (which is entirely possible), then the square/rectangle "problem" goes away. Either you have an object that cannot be modified (because, say, an apple will never become an orange) and hence "OO using immutable objects" to implement such an object is a wise OOP choice **OR** you have an object that can be modified and hence it is never a "square": it is still a rectangle, a rectangle that, in some state, appears to looks like a square but really ain't. – SyntaxT3rr0r Dec 03 '10 at 18:38

5 Answers5

12

If you make Square and Rectangle immutable, then you won't violate LSP.

The issue is if you can independently change the width and height of a Rectangle, and a Square is a Rectangle, then you can change a Square to not be a square.

Laurence Gonsalves
  • 137,896
  • 35
  • 246
  • 299
  • 4
    Yes, the point of inheritance is that a derived type should *add* features, and not violate any of the superclass's existing features. – David R Tribble Dec 03 '10 at 18:29
1

I would say: Don't

A square is a special case of a rectangle. So: use rectangles. Its not clear that there is any good reason to have a distinct square class.

Of course, that really depends what you are doing with these shapes. Whether or not LSP is satisfied depends on the operations you have on your shapes.

Winston Ewert
  • 44,070
  • 10
  • 68
  • 83
  • If a function can only operate with rectangles whose sides are equal and accepts a parameter of type "ImmutableSquare", there's no need for a run-time check that the length and width are equal. To pass an "ImmutableRectangle" to such a function, one would have to use a narrowing typecast; if the sides aren't equal, the typecast could throw, but one that's expected of narrowing typecasts. There would be no danger of the function itself throwing as a result of being given a non-square rectangle. – supercat Dec 03 '10 at 18:59
  • @supercat, you certainly can do that and it works. But my point was that if you have code to deal with rectangles, there is a good possibility that you have no need to implement special square code. Just use the rectangle version. For everything I can think of a square doing, (drawing, area, perimeter, etc) the rectangle version will do the same. Perhaps you have a case where that isn't true and in such cases, your solution is great. – Winston Ewert Dec 03 '10 at 21:55
  • In the particular case of simple shapes, that's probably true, but the principle applies much more broadly. For example, one could have an immutable LinearTransfrom2d class which can represent any 2d linear transform, and have a derived OrthogonalTransform2d class which represents only transforms where the xy and yx components are zero. Certain graphical operations would only be permitted using OrthogonalTransform2d, while others would accept any LinearTransform2d. – supercat Dec 03 '10 at 23:56
  • @supercat, sure that kind of things works in general. It all depends what you are doing with your objects. – Winston Ewert Dec 04 '10 at 01:42
0

You'd be better off with passing a constraint in the constructor (bool square would do) storing that as a field, and checking the fields (x, y, w, h?) during calculations for 'squareness' thus speeding elements of these calculations up.

You could make it so that if the 'square' constraint is set, setting width or height would cause the other one to match automatically. The set(x, y, w, h) method would always work, but would throw an IllegalArgumentException or such if the arguments didn't give a square.

Chris Dennett
  • 22,412
  • 8
  • 58
  • 84
0

If they are immutable, as stated above than it does not violate LSP:

public class Rectangle {
    int width;
    int height;

    public Rectangle(int w, int h) {
        width = w;
        height = h;
    }

    //getWidth(), getHeight, getArea(), etc, but no setters.
}


public Square extends Rectangle {
    public Square(int side) {
        super(side, side);
    }
}

Now if you had a scale() method that took a percentage you could grow the rectangle and square in an LSP-compliant way, but a grow() method on rectangle that took two sides that's overridden by square to behave correctly, of course, would violate LSP.

Todd
  • 3,438
  • 1
  • 27
  • 36
0

Clinton put it the best: it depends on what the definition of is is

The unshakable intuition that a square is a rectangle comes from our mathematical training. Mathematical objects are immutable and identity-less. If your program indeed is modeling square and rectangle objects in the mathematical sense, then Square should be a subtype of Rectangle, and they should be immutable. Any mathematical operations that applicable to Rectangle are applicable to Square.

However, your program may not be modeling mathematical objects. Maybe you are modeling graphic screen objects. There are mathematical aspects in them, but then there are more. Then we are in a mess. Maybe it's better to design Rectangle as subtype of Square, considering all the operations that you want to put on them. Then it's completely against our mathematical intuition, and we do not want that kind of confusion in our design.

This is a horrible truth: OOP is meh. You may have thought that some super smart people did some grandiose research and came up with this omnipotent programming model. For every puzzle there is a perfect solution, you just don't know it because you haven't become good enough in understanding this divine revelation. People argue about OOP with more zeal than religious enemies, throwing big words and abstract concepts at each other, quoting principles and conventions from ancient texts which nobody really understands.

irreputable
  • 44,725
  • 9
  • 65
  • 93