心法
軟體中的對象(類,模塊,函數等等)應該對於擴展是開放的,但是對於修改是封閉的 。
意思代表盡量在不修改原本程式碼下,進行擴充。
範例
有個遊戲彩金計算方式,免費遊戲算法公式如下。
<?php class Payoff { public function calculator($info) { $payoff = 0; if($info['mode'] == 'freegame'){ $iPayoff += $info['money'] * $info['odds'] * 0.3; } return $payoff ; } } $oMod = new Payoff(); $payoff = $oMod->calculator(array('mode' => 'freegame','money' => 25, 'odds' => 10)); print_r($payoff );
現在遊戲多個計算獎金遊戲,所以需要增加計算派彩的的判斷。
<?php class Payoff { public function calculator($info) { $payoff = 0; if ($info['mode'] == 'freegame') { $payoff += $info['money'] * $info['odds'] * 0.3; } elseif ($info['mode'] == 'bonusgame') { $payoff += $info['money'] * $info['odds'] * 0.2; } return $payoff ; } } $oMod = new Payoff(); $payoff = $oMod->calculator(array('mode' => 'bonusgame', 'money' => 25, 'odds' => 10)); print_r($payoff );
如果之後又有新的小遊戲,程式就要一直修改,如果不小心把沒問題的程式改出問題來,不就更加難維護了。
單元測又要一直寫很多個。這就沒有符合開放閉合模式的原則。
解決方式(開放封閉)
<?php class Payoff { public function calculator(Calculator $calculator) { return $calculator->calculate(); } } abstract class Calculator { protected $basePayoff; public function __construct($info) { $this->basePayoff = $info['money'] * $info['odds']; } abstract public function calculate(); } class FreeGame extends Calculator { public function calculate() { return $this->basePayoff * 0.3; } } class BonusGame extends Calculator { public function calculate() { return $this->basePayoff * 0.2; } } $mod = new Payoff(); $calculator = new FreeGame(array('money' => 25, 'odds' => 10)); $payoff = $mod->calculator($calculator); print_r($payoff); //75 echo '<br/>'; $calculator = new BonusGame(array('money' => 25, 'odds' => 10)); $payoff = $mod->calculator($calculator); print_r($payoff); //50
藉由抽象或者介面來擴充。以後只要新增新的計算派彩的物件就可以了,主程式class payoff也不必一直修改。單元測試我們只要專心測試計算派彩的方法就行。這就符合開放封閉。
遵守開放封閉好處
- 可維護性,由於減少對原有程式修改,減少了原功能出現問題的機率。
- 容易測試,原本if .. else 會讓該功能需要較多的測試案例,現在可以讓他們獨立被測試。
- 利用性,功能重複利用的機率提高了。
相關文章:
- PHP物件導向 – 三大特性:封裝(Encapsulation)、繼承(Inheritance)、多型(Polymorphism)
- PHP物件導向 – 單一職責(Single Responsibility Principle, SRP)
- PHP物件導向 – 開放封閉(Open Closed Principle, OCP)
- PHP物件導向 – 里氏替換(Liskov Substitution Principle, LSP)
- PHP物件導向 – 最小知識(Least Knowledge Principle, LKP)
- PHP物件導向 – 介面隔離(Interface Segregation Principle, ISP)
- PHP物件導向 – 依賴反轉(Dependency-Inversion Principle, DIP)