“一个软件实体如果使用的是一个基类的话,一定适用于其子类,而且根本不能觉察出基类对象和子类对象的区别。”
陈述:
若对每个类型S的对象o1,都存在一个类型T的对象o2,使得在所有针对T编写的程序P中,用o1替换o2后,程序P的行为功能不变,则S是T的子类型。
通俗地讲,就是子类型能够完全替换父类型,而不会让调用父类型的客户程序从行为上有任何改变。
意义:
我们在客户程序在调用某一个类时,实际上是对该类的整个继承体系设定了一套约束,继承体系中的所有类必须遵循这一约束,即前置条件和后置条件必须保持一致。这为对象继承加上了一把严格的枷锁。显然,LSP原则对于约束继承的泛滥具有重要意义。
class Rectangle
{
private:
long width;
long height;
public:
void setWidth(long width)
{
this->width = width;
}
long getWidth()
{
return this->width;
}
void setHeight(long height)
{
this->height = height;
}
long getHeight()
{
return this->height;
}
};
//正方形类
class Square
{
private:
long side;
public:
void setSide(long side)
{
this->side = side;
}
long getSide()
{
return side;
}
};
//正方形类(如果继承自长方形类):
class Square : public Rectangle
{
private:
long side;
public:
void setWidth(long width)
{
setSide(width);
}
long getWidth()
{
return getSide();
}
void setHeight(long height)
{
setSide(height);
}
long getHeight()
{
return getSide();
}
long getSide()
{
return side;
}
void setSide(long side)
{
this->side = side;
}
};
class SmartTest
{
public:
void resize(Rectangle r)
{
while (r.getHeight() <= r.getWidth() )
{
r.setWidth(r.getWidth() + 1);
}
}
};
class Quadrangle
{
public:
virtual long getWidth() = 0;
virtual long getHeight() = 0;
};
Quadrangle类只声明两个取值方法,不声明任何的赋值方法。
class Rectangle : public Quadrangle
{
private:
long width;
long height;
public:
void setWidth(long width)
{
this->width = width;
}
long getWidth()
{
return this->width;
}
void setHeight(long height)
{
this->height = height;
}
long getHeight()
{
return this->height;
}
};
//正方形类:
class Square : public Quadrangle
{
private:
long side;
public:
void setSide(long side)
{
this->side = side;
}
long getSide()
{
return side;
}
long getWidth()
{
return getSide();
}
long getHeight()
{
return getSide();
}
};
问题如何得以避免?
参考资源:
《设计模式:可复用面向对象软件的基础》,ERICH GAMMA RICHARD HELM RALPH JOHNSON JOHN VLISSIDES著作,李英军 马晓星 蔡敏 刘建中译,机械工业出版社,2005.6
《敏捷软件开发:原则、模式与实践》,Robert C. Martin著,邓辉译,清华大学出版社,2003.9
《设计模式解析》,Alan Shalloway等著(徐言声译),人民邮电出版社,2006.10