Tuesday, May 24, 2011

The Square and Rectangle problem OR Circle and Eclipse Problem

Most people would think that a Square is a special kind of Rectangle and therefor intuitively inherit their Square class from the Rectangle class to be able to reuse code. Similar way goes for Circle and eclipse, where circle is considered eclipse's extension and special case.

Notice that the Rectangle have a couple of traits that the Square does NOT and vice versa. First of all the Square has only *ONE* attribute; size, while the Rectangle have *TWO* attributes; width & height. And this fact may for some problems be quite tricky to discover sometimes. And if you do the capital sin of inheriting your Square class from your Rectangle class, then you might currently get around it by hiding the width property of the Rectangle somehow, maybe by convention, and then just let the size property of the Square forward the call to height or something similar, but this is always wrong!

So consider the rectangle class:
public class Rectangle   
    private double width;  
    private double height;  
    public void SetWidth (double w) { width = w; }  
    public void SetHeight (double h) { height = h; }  
    public void GetWidth () { return w; }  
    public void GetHeight () { return h; }  
    public void GetArea () { return width * height; }  

Consider the square class:
public class Square  
    private Rectangle r;  
    public void SetWidth (double x) { r.SetWidth (x); r.SetHeight (x); }  
    public void SetHeight (double x) { r.SetWidth (x); r.SetHeight (x); }  
    public void GetWidth () { return r.GetWidth; }  
    public void GetHeight() { return r. GetHeight; }  
    public void GetArea () { return r. GetArea; }  

But Square has to somehow guarantee that its width and height are same or in other words height is redundant. So if client changes height, it has to change width accordingly.
Why is it that the client code gets affected by the derived class object reference being given in place of a base class object reference? Because the derived class's post-condition is weaker than that of the base class. The base class promises that if you call the SetHeight function, it will change the value of the height, but will do nothing to the value of width. But nothing like that happens in derived class and therefore, a client who is relying on the above base class gets affected when it gets a derived class object reference instead.

Therefore, inheritance is not the right approach in this situation. Delegation is the right choice. See here for solution to this problem.

No comments:

Post a Comment