0

My previous question was just with class diagram and because of some comments I thought I try to find an example with a little piece of code for the diagram to see if principles correct understood?

enter image description here

class Rectangle {
  private int width, height;

  public void setHeight(int h) { height = h; }
  public void setWidth(int w) { width = w; }
  public int area() { return height * width; }
}

class Square extends Rectangle {
  public void setHeight(int h) { height = width = h; }
  public void setWidth(int w) { width = height = w; }
}

// A test function for rectangles
public void areaTest(Rectange rect) {
  rect.setHeight = 20;
  rect.setWidth = 10;
  int area = rect.area();

  assert area == 200;
}

I think first problem is that Liskov Substitution Principle is hurt because square extends rectangle so there is no issue saying a square is a rectangle but you cannot say a rectangle is a square which the code does, so this principle is hurt I think for this reason.

Another hurt principle I believe is Single-Responsibility Principle because in class rectangle, in order to modify the properties of a rectangle for example its area(), you would need to change the entire implementation to achieve this, for the similar reason I believe the Open/Closed Principle is hurt as well because if you want add an extension let's say a draw function to draw the objects (rectangle/square), you cannot do this correctly.

I think other principles are not hurt by this design.

  • 1
    Open Close Principle not violated here because your classes don't have other dependencies. It possibly can be violated in case when rectangle will have Draw method and inside that method you will instantiate "Drawing" objects and draw rectangle. So when you want to draw rectangle differently(add fill colour) you will need make changes into rectangle class. In that case OCP will be violated, and correct solution would be introduce drawing as separated class and pass it to rectangle as a dependency. – Fabio Nov 18 '18 at 18:35
  • 1
4

There is no problem with the Single Responsibility Principle. The SRP doesn't say that the class shall do only one thing. It says that it should have only one reason to change. Some will argue that this implies that it should have only one single purpose. So for a shape, setting the dimensions and calculating a couple of shape related properties seems perfectly fine !

There is indeed a problem with the Liskow Subsittution Principle, since setting the height also changes the width. This might break the post-conditions of the setters (depending on how these post-conditions are expressed). And it breaks in any case the history constraint, that says that the properties of the Rectangle should only be changed according to the primitives of the Rectangle interface (i.e. no unexplained change).

Edit: This time, there is no issue with Interface Segregation Principle (thanks to the side effects when changing length or width). Dependency inversion is not relevant here either.

On the Open/CLosed, there's some room for discussion. The private variables should not be used by the extension, since it is an implementation detail of Rectangle and Square should not know about it. So it's not so open for extension: if the class would change the way it manages the heigth and the width, the extension would no longer work. So Square should use only the public interface. To improve the situation you could consider separating the interface of Rectangle from its implementation. But this could be an overkill in such a simple case.

  • Oh alright then really only this Liskow principle is hurt and no others? Thank you for explaining why SRP is unhurt by the way :) – tenepolis Nov 18 '18 at 17:56
  • I don't think Liskov Substitution Principle violated here. You can replace square with rectangle and your application will still work. Of course output will be different, but we use inheritance for the situations where base and derived classes need to have different behaviour. LSP will be violated when you will not be able to use rectangle instead of sqare. For example you override setHeight and throw an exception if height is les then 10 in square class. – Fabio Nov 18 '18 at 18:25
  • 3
    @Fabio The Square–Rectangle Problem is the classic example to illustrate the LSP. I think you are reading the LSP backwards: it's about whether the Square interface satisfies the Rectangle interface, i.e. whether you can use a Square wherever a Rectangle is expected. This is not the case, e.g. the test case in the question that describes the semantics of a Rectangle fails when given a Square. – amon Nov 18 '18 at 20:07
  • 1
    @Fabio according to Barabar Liskov in this article the history constraint is definitively violated. It's not only about using the subtype, but also about making conclusions about state, invariants, and post-conditions based on the methods invoked. And square creates unexpected changes that are not explained only by calls on a rectangle. – Christophe Nov 18 '18 at 20:20
  • 1
    The point within the Square-Rectangle Problem is that the Rectangle base class allows for independent modifications of width and height, and that can't be respected in a Square subclass. Anyway, I'd already question the basic approach of having a single individual Rectangle change its properties after creation. I'd instead advocate Rectangle to be immutable, then the problem vanishes. – Ralf Kleberhoff Nov 18 '18 at 20:22

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.