んだです。メモです。
開放/閉鎖原則(open/closed principle、OCP) とは?
定義
「モジュールは拡張に対して開いて (Open) おり,修正に対して閉じて (Closed) いなければならない」
拡張に対して開いているって? (Open)
仕様変更があった場合に、新しいコードを追加するだけで目的を達成できる
修正に対して閉じているって?? (Closed)
仕様変更があった場合に、クラスを修正する必要がないこと
この2つを同時に満たしている必要があります。
OCP違反なコード
ランジェリーショップの割引価格を扱うクラスがあったとします。
パンティーなら、0.5
ブラジャーなら、0.2
の割引率。
class DiscountCalculator { public function calculate(object $itemType, int $itemPrice, int $unitTotal): float { $discount = 0; if ($itemType instanceof UnderWear) { $discount = $this->getDiscountPrice(0.5, $itemPrice, $unitTotal); } elseif ($itemType instanceof Bra) { $discount = $this->getDiscountPrice(0.2, $itemPrice, $unitTotal); } return $discount; } private function getDiscountPrice(float $discount, int $itemPrice, int $unitTotal) { return ($itemPrice * $unitTotal) * $discount; } }
このランジェリーショップに、こんな仕様変更があったとする
パンストも商品として取り扱いたい、もちろん割引(0.4)もありで!!
この仕様変更に対しては、DiscountCalculatorクラスを修正する必要があります。。
これがOCP違反。
public function calculate(object $itemType, int $itemPrice, int $unitTotal): float { $discount = 0; if ($itemType instanceof UnderWear) { $discount = $this->getDiscountPrice(0.5, $itemPrice, $unitTotal); } elseif ($itemType instanceof Bra) { $discount = $this->getDiscountPrice(0.2, $itemPrice, $unitTotal); // パンストの条件を追加 } elseif ($itemType instanceof Pansuto) { $discount = $this->getDiscountPrice(0.4, $itemPrice, $unitTotal); } return $discount; }
リファクタリング
// ItemInterface.php interface ItemInterface { public function setDiscountValue($discountValue); public function getDiscountValue(); } // UnderWear.php class UnderWear implements ItemInterface { private $discountValue; public function setDiscountValue($discountValue) { $this->discountValue = $discountValue; } public function getDiscountValue() { return $this->discountValue; } } // DiscountCalculator.php class DiscountCalculator { /** * @param ItemInterface $itemType * @param int $itemPrice * @param int $unitTotal * @return float */ public function calculate(ItemInterface $itemType, int $itemPrice, int $unitTotal): float { return ($itemPrice * $unitTotal) * $itemType->getDiscountValue(); } }