エンジニアの前田です。
概要
OpenClosedの原則について、wikipediaではこう↓あります
ソフトウェア要素(クラス、モジュール、関数など)は、拡張に対しては開いており、修正に対しては閉じているべきである。 わかりやすく説明すると、機能追加や修正の際に対象の箇所以外の既存のソースコードを変更する必要がないプログラムのことです。 ポリモーフィズムを使用する方法が、OpenClosedの原則に従った実装の典型としてよくあげられています。
例
悪い例から示します。 全自動で飲み物をしてくれるAutoTakeDrinkクラスがあります。 要件として料理に合わせた飲み物を提供する必要があります。 以下、疑似コードです。
class AutoTakeDrink { public takeDrinks(foods) { const drinks = foods.map(f => { if (instansof food === 'ChineseFood') { return new ChinaTea(); } else if (instansof food === 'ItalianFood') { return new Wine(); } else if (instansod food === 'JapaneseFood') { return new JapanTea(); } }); return drinks; } }
上のやり方だと、料理の種類が増えるたびにAutoTakeDrinkクラスのtakeメソッドのif文の分岐を追加する必要が出てきます。 料理の種類を追加がAutoTakeDrinkクラスにも影響を及ぼしてしまうのでOpenClosedの原則に従った実装ではありませんね。
以下にOpenClosedの原則に従った実装を示します。
// まずは各料理クラスが共通のインターフェイス、Foodに従って実装するようにします。 // Foodインターフェイスに従っているクラスは必ずsuitableDrinkメソッドを実装する必要があります。 interface Food { public suitableDrink(): Drink } class ItalianFood implements Food { suitableDrink() { new Wine(); } } class ChineseFood implements Food { suitableDrink() { new ChinaTea(); } } class JapaneseFood implements Food { suitableDrink() { new JapanTea(); } } class AutoTakeDrink { public takeDrinks(foods: Food[]) { const drinks = foods.map(f => { return f.suitableDrink(); }); return drinks; } }
各料理クラスが飲み物を返すsuitableDrinkメソッドを実装することで、 新しい料理を追加した時にAutoTakeDrinkクラスにif文の分岐を追加する必要がなくなりました。 以上が、ポリモーフィズムを使用しOpenClosedの原則に従った実装をした例です。