八葉の日記

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

SOLID原則:2つ目 オープン・クローズドの原則(OCP:Open-Closed Principle)

〇オープン・クローズドの原則(OCP:Open-Closed Principle)
1.拡張に対して開かれている
2.修正に対して閉じている

1つ目はモジュールの振る舞いを変更できること、2つ目はモジュールの振る舞いを拡張しても、
そのモジュールのソースコードやバイナリは影響を受けないことを示します。
簡単にいうと、ソースコードをいじらなくてもモジュールの振る舞いを変更できるということを
いっています。

OCPを守ってないケースから、守っているケースへ設計を修正していきながら
説明していきます。

例えば、GUIで複数画面を表示する設計を考えます。
画面の例:商品画面と商品の説明画面を表示する
f:id:konboi_kun:20171112171740p:plain
このソフトウェアには以下のような画面追加が拡張として予測できます。
f:id:konboi_kun:20171112172913p:plain

〇OCPに従わない設計
単純にクラス設計すると以下のような感じになり、コードはそれぞれに対して
createを呼ぶという感じになると思うのですが、これは予測した拡張に対して、
コードの修正が必要です。
f:id:konboi_kun:20171112172719p:plain

//すべてのWindowを表示する
void Display::Create()
{
	//Picture部分の生成
	picture.Create();

 	//Detaile部分の生成
	detaile.Create();
}

f:id:konboi_kun:20171112174833p:plain

//すべてのWindowを表示する
void Display::Create()
{
	//Picture部分の生成
	picture.Create();

 	//Detaile部分の生成
	detaile.Create();

 	//Review部分の生成 ← 画面追加の度に追加が必要
	review.Create();
}

〇OCPに従った設計
f:id:konboi_kun:20171112175255p:plain
WindowIFというInterfaceクラスを用意し、Displayはこのクラスに依存するようにします。
すると以下のようにコードすることができます。
このコードは今後どれだけWindowが追加拡張されても、修正は不要です。

//すべてのWindowを表示する
void Display::Create()
{
	typedef vector< WindowIF* > Container;
	for (Container::iterator p = container.begin();
             p != container.end();
             ++p)
        {
                (*p)->create()
        }
}

最後にですがOCPの原則を適用するにはモジュールに対しての共通性と可変性の分析が必要になってきます。
分析した可変性に対してInterfaceのような抽象を用いることで、変更に対しての修正が発生しないように
するのですが、抽象自体の意味が後々変わった場合は修正が必要になります。
これを避けるためには、しっかりとした共通性分析を可変性分析が必要になってきます。

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

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