Tuesday, March 11, 2008

Solving Bob's Problem

Reading up on Liskov Substitution Principle last night finaly put me over the top to start blogging about software development. I had a copy of Robert C. Martin's article published on the Object Mentor webpage (direct link) where he suggest that deriving Square from Rectangle violated LSP.

Here is his code example:

class Rectangle {
public:
virtual void SetWidth(double w) {itsWidth=w;}
virtual void SetHeight(double h) {itsHeight=h;}
double GetHeight() const {return itsHeight;}
double GetWidth() const {return itsWidth;}
private:
double itsWidth;
double itsHeight;
};

Sparing you the declaration of the Square class, which inherits Rectangle, here's how it differs. It overrides SetWidth and SetHeight, calling them both in the base class.

void Square::SetWidth(double w) {
Rectangle::SetWidth(w);
Rectangle::SetHeight(w);
}

void Square::SetHeight(double h) {
Rectangle::SetHeight(h);
Rectangle::SetWidth(h);
}

This will violated LSP since a client may call SetHeight with one number and SetWidth with another and presume that GetHeight will return what ever number SetHeight was called with - which will of couse not be the case.

He leaves us no solution in his article, so we're left to think that a Square never should inherit a Rectangle. I myself should in this simple case make the objects immutable. Aside from all other benefits it will also make the objects pass the LSP test.

class Rectangle
{
public:
Rectangle(double w, double h) {itsWidth=w; itsHeight=h;}
double GetHeight() const {return itsHeight;}
double GetWidth() const {return itsWidth;}
private:
double itsWidth;
double itsHeight;
};

class Square : public Rectangle
{
public:
Square(double side) : Rectangle(side, side) {}
};

No comments: