闡述:子類型(subtype)必須能夠替換掉它們的基類型(basetype)
先提出一個問題:正方形是不是一種特殊的長方形(IS - A關系)?
先不要回答這個問題,看下面的分析。
理解:LSP原則的一個例子,假如有個people的基類,兩個字類man類和woman類,都繼承於people類。那么針對people類的任何操作,比如fun吃飯、fun睡覺、fun走路,對於man類和woman類都成立。這個很好理解,不管是man還是woman,歸根結底,還都是一個people。
(一)正常思維
如下例子:
class CShape
{
public:
CShape(void);
~CShape(void);
public:
virtual void Draw();
};
class CCircle:public CShape
{
public:
CCircle(void);
~CCircle(void);
public:
virtual void Draw();
};
class CSquare:public CShape
{
public:
CSquare(void);
~CSquare(void);
public:
virtual void Draw();
};
在使用CShape對象的任何地方,都可以使用CCircle對象或者CSquare對象。
(二)、特殊情況呢?
回到最初的問題,正方形是不是矩形的問題。
如下類:
class CRectangle
{
public:
CRectangle(void);
~CRectangle(void);
protected:
int width;
int height;
};
class CSquare:public CRectangel
{
public:
CSquare(void);
~CSquare(void);
};
假如有個函數
void g(CRectangle * r)
{
r.width = 4;
r.height = 5;
if( r.Area() != 20)
break;
}
請問,對於函數g來說,能用一個CSquare對象,代替CRectangle對象嗎?很明顯,不能!
很明顯,違反了LSP原則。
那么,正方形到底是不似乎矩形呢?也就是說CSquare和CRectangle之間,是否存在(IS - A)關系呢?
解釋:
1、從屬性方面講,正方形是矩形,是一種特殊矩形,即width = height;
2、從行為方式將,正方形可能不是矩形。
比如,對於函數g來說,描述了矩形的一種行為方式,很明顯,正方形不符合這種行為方式。
OOD中的IS-A關系,是就行為方式而言的,行為方式是可以進行合理假設的。而行為方式,才是我們進行面向對象軟件設計真正所關注的問題。
因此,可以講,正方形不是一個矩形。
(三)、怎么處理此類問題呢?
1、基於契約進行設計。
每個類設計時,都會有一些假設,每個方法,都有前置條件,后置條件,這些條件都是契約。對這些方法,要注明契約。
要想從基類派生子類,就必須滿足這些契約。如果不滿足這些契約,就不能繼承出子類。(即使他們看起來很像,比如正方形與矩形)
2、但是我們又需要LSP原則,怎么辦呢?
從CRectangle類和CSquare類,提取出公共部分,做為一個基類。比如CShape類。
CRectangle和CSquare都繼承自CShape類。
具體一些例子,參考《敏捷軟件開發》相關章節