八葉の日記

日々、感じたことをまとめる場として利用する

SOLID原則:3つ目 リスコフの置換原則(LSP:Liskov-Substitution Principle)

〇リスコフの置換原則(LSP:Liskov-Substitution Principle)
派生型は基本型と置換可能でなければならない

上の意味だけ聞いてもなんのこっちゃとなるとおもうのですが、
リスコフの置換原則に反したケースを皆さん見たことがあると思います。

class MainScreen : public Screen
{
        virtual void Disp();
	~省略~
};

class SubScreen : public Screen
{
         virtual void Disp();
	~省略~
};

void Display(Screen* p)
{
	if (typeid(p) == typeid(MainScreen))※RTTIはイメージのために使っているので実際にこのコードを入れても動作しないと思います。
        {
               static_cast<MainScreen* >(p)->Disp();
        }
        else if (typeid(p) == typeid(SubScreen ))
        {
               static_cast<SubScreen * >(p)->Disp();
        }
}

クラスの型を見て処理を変える、コードをみたことはあるんじゃないでしょうか。。。。
ここでは、MainScreen とSubScreen がScreenの代わりに使えていません。こういうときにリスコフの置換原則に反しているといえます。

ここでDisp関数はvirtual関数なんだからif文はいらないじゃないかという方は正しいです。
上の例のコードにリアリティを付けるとこんな感じになると思います。

void Display(Screen* p)
{
	if (typeid(p) == typeid(MainScreen))
        {
     PreFuncMain(); //当初は予定していませんでしたが、度重なる仕様変更でMainの前にはDispに関係ない処理がどうしても必要です。
           //この処理はMainScreenクラスで実行するのはムリです。もしくは変更にコストがかかります。
               static_cast<MainScreen* >(p)->Disp();
        }
        else if (typeid(p) == typeid(SubScreen ))
        {
               static_cast<SubScreen * >(p)->Disp();
        }
}

■リスコフの置換原則を守るためには
リスコフの置換原則を守るためには、契約による設計を導入するということが
挙げられています。
契約による設計とは、クラスに不変条件、メソッドに事前条件と事後条件を決めることです。
もうこれを破れば継承関係を持たせるべきでないかもしれないという尺度になると思います。

アジャイルソフトウェア開発の奥義 第2版 オブジェクト指向開発の神髄と匠の技

アジャイルソフトウェア開発の奥義 第2版 オブジェクト指向開発の神髄と匠の技