<?php /** * 接下來看的是策略模式,舉得例子是商場搞活動 * 商場搞活動中須要不停的變化促銷方式,有打折啦,滿減啦,積分啦等等,並且打折力度也不同,積分也不同 * 因此就須要使用策略模式,將變化封裝。策略模式的主要特色就是封裝變化,那爲何不使用工廠模式呢, * 每一次有活動我在工廠中新增一個選項,而後實例化一個新的類,這樣不也是能夠麼。那就下了就對比一下兩個模式的不同, * 看看爲何使用策略模式 */ // 先從最基礎的構建開始,實現一個最簡單的功能,不須要考慮封裝繼承等 // 服務端 $total = 0; function shop($price, $commodity) { $total = round($price * $commodity, 2); return $total; } // 客戶端 $total = shop(1.2, 2); echo $total;
<?php // 上述實現了正常銷售狀況,那接下來經理須要搞活動,要給商品打折,有不一樣的打折力度 // 服務端 $total = 0; // 0: 五折, 1:8折, 2:9折 function shop($price, $commodity, $type) { switch ($type) { case '0': $total = round($price * $commodity, 2) * 0.5; break; case '1': $total = round($price * $commodity, 2) * 0.8; break; case '2': $total = round($price * $commodity, 2) * 0.9; break; default: return 'error'; } return $total; } // 客戶端 $total = shop(1.2, 2, 1); echo $total; /** * 新增長了打折力度後,服務端須要修改的地方就比較多,若是如今經理又須要添加滿減的活動,有的要滿減,有的要在打折的基礎上滿減 * 若是按照當前的架構來實現的話,只能是在switch中不斷的添加新的選項,同時要和客戶端約定好0是什麼,1是什麼等等,若是商場開了5年 * 經理搞活動搞了2,300次,並且每次還搞的不同,那這個代碼將變的很龐大,很很差維護,並且客戶端與服務端對於type的約定也會致使bug的產生 * 所以此處就須要使用面向對象的三大特性,以前還學習了簡單工廠模式,正好用來實現這個功能 * 實現思路: * 1,將折扣封裝成一個抽象類, * 2,而後不一樣的折扣規則繼承這個抽象類 * 3,新建一個建立工廠類,而後根據不一樣的打折規則,實例化不一樣的折扣規則 */
<?php // 抽象收費基類 abstract class CashSuper{ public abstract function acceptCash($money); } // 正常收費類 class CashNormal extends CashSuper { public function acceptCash($money) { return $money; } } // 打折收費類 class CashRebate extends CashSuper { private $moneyRebate = 1; public function __construct($moneyRebate) { $this->moneyRebate = $moneyRebate; } public function acceptCash($money) { // TODO: Implement acceptCash() method. return $money * $this->moneyRebate; } } // 滿減活動類 class CashReturn extends CashSuper { // 滿減活動須要有滿減的條件和滿減的值,輸入300,100就是滿300減去100 private $moneyCondition = 0; private $moneyReturn = 0; public function __construct($moneyCondition, $moneyReturn) { $this->moneyCondition = $moneyCondition; $this->moneyReturn = $moneyReturn; } public function acceptCash($money) { $result = $money; if ($money >= $this->moneyCondition) { $result = $money - floor($money / $this->moneyCondition) * $this->moneyReturn; } return $result; } } // 建立工廠內,實現自動實例化對象 class CashFactory { private $cs = null; public function cteateCashAccept($type) { switch ($type) { case '正常收費': $this->cs = new CashNormal(); break; case '打折': $this->cs = new CashRebate(0.8); break; case '滿300減100': $this->cs = new CashReturn(300, 100); break; default: return 'error'; } return $this->cs; } } // 客戶端 $csf = new CashFactory(); $cs = $csf->cteateCashAccept('正常收費'); $res = $cs->acceptCash(100); echo $res; $cs = $csf->cteateCashAccept('打折'); $res = $cs->acceptCash(100); echo $res; $cs = $csf->cteateCashAccept('滿300減100'); $res = $cs->acceptCash(600); echo $res; /** * 上述方法是使用簡單工廠實現的,可是仍是具備缺點的,比較以前實現計算器的時候, * 計算器的規則是固定的,不會頻繁的改動,可是在此處這些促銷算法是不斷更新的 */
<?php /** * 針對上述問題,如今就能夠引出策略模式 * 先看到策略模式的概念: * 策略模式定義了算法家族,分別封裝起來,讓他們之間能夠互相替換,此模式讓算法的變化,不會影響到使用算法的用戶 * 接下來使用策略模式實現此功能,而後參照代碼理解上邊的概念 */ // 抽象收費基類 abstract class CashSuper{ public abstract function acceptCash($money); } // 正常收費類 class CashNormal extends CashSuper { public function acceptCash($money) { return $money; } } // 打折收費類 class CashRebate extends CashSuper { private $moneyRebate = 1; public function __construct($moneyRebate) { $this->moneyRebate = $moneyRebate; } public function acceptCash($money) { // TODO: Implement acceptCash() method. return $money * $this->moneyRebate; } } // 滿減活動類 class CashReturn extends CashSuper { // 滿減活動須要有滿減的條件和滿減的值,輸入300,100就是滿300減去100 private $moneyCondition = 0; private $moneyReturn = 0; public function __construct($moneyCondition, $moneyReturn) { $this->moneyCondition = $moneyCondition; $this->moneyReturn = $moneyReturn; } public function acceptCash($money) { $result = $money; if ($money >= $this->moneyCondition) { $result = $money - floor($money / $this->moneyCondition) * $this->moneyReturn; } return $result; } } // 原先封裝好的具體活動規則視爲3個策略 // 接下來使用策略模式的 context 上下文處理類,就像簡單工廠模式具備建立工廠類同樣 class CashContext { private $cs = null; // 使用構造方法,在實例化此類的時候,就須要將使用的策略傳遞進來 public function __construct(CashSuper $cs) { $this->cs = $cs; } public function getResult($money) { return $this->cs->acceptCash($money); } } // 客戶端實現 function shop($type, $money) { $cs = null; switch ($type) { case '正常收費': $cs = new CashContext(new CashNormal()); break; case '滿300減100': $cs = new CashContext(new CashReturn(300, 100)); break; case '打折': $cs = new CashContext(new CashRebate(0.8)); break; } $res = $cs->getResult($money); return $res; } $res = shop('滿300減100', 600); echo $res; /** * 此處使用了策略模式,使用了上下文處理類,調用者須要使用哪一種策略將對應的策略傳給進來就好 * 到此處就有些懵逼,這策略模式和簡單工廠模式到底有什麼區別啊,並且還把判斷邏輯移動到客戶端去處理 * 難道每一個使用此類的方法都本身去判斷啊? * * 若是這樣思考那就片面了,並非要去對比兩個模式哪一個好哪一個壞,並且每當碰到這種需求的時候,要學會使用哪一種模式去解決當前遇到的問題 * 此處使用策略模式,能夠很好的將具體算法和客戶端進行了隔離,在未使用策略模式的時候,須要客戶端本身去調用算法的實現方法, * 這樣作的好處是什麼呢,就是下降耦合性,像在此處客戶端只接觸到了CashContext類,以及他認爲的算法實現方法getResult; * 這都是屬於CashContext類的,可是在工廠模式中就須要使用到具體算法的實現方法acceptCash。 * 咱們使用策略模式很好的進行了封裝隔離,只將上下文處理類中的一個方法暴露給客戶端,大大下降了耦合性,客戶端升級,服務端升級改動等均可以 * 很輕鬆的進行。那此處應當理解的就是封裝變化,封裝變化能夠下降耦合性。 */ // 可是此處將判斷邏輯放到客戶端是很差的,那解決方案就是結合簡單工廠模式,將策略模式有簡單工廠模式結合使用
<?php // 抽象收費基類 abstract class CashSuper{ public abstract function acceptCash($money); } // 正常收費類 class CashNormal extends CashSuper { public function acceptCash($money) { return $money; } } // 打折收費類 class CashRebate extends CashSuper { private $moneyRebate = 1; public function __construct($moneyRebate) { $this->moneyRebate = $moneyRebate; } public function acceptCash($money) { // TODO: Implement acceptCash() method. return $money * $this->moneyRebate; } } // 滿減活動類 class CashReturn extends CashSuper { // 滿減活動須要有滿減的條件和滿減的值,輸入300,100就是滿300減去100 private $moneyCondition = 0; private $moneyReturn = 0; public function __construct($moneyCondition, $moneyReturn) { $this->moneyCondition = $moneyCondition; $this->moneyReturn = $moneyReturn; } public function acceptCash($money) { $result = $money; if ($money >= $this->moneyCondition) { $result = $money - floor($money / $this->moneyCondition) * $this->moneyReturn; } return $result; } } // 原先封裝好的具體活動規則視爲3個策略 // 接下來使用策略模式的 context 上下文處理類,就像簡單工廠模式具備建立工廠類同樣 class CashContext { private $cs = null; // 使用構造方法,在實例化此類的時候,就須要將使用的策略傳遞進來 public function __construct($type) { switch ($type) { case '正常收費': $cs = new CashNormal(); break; case '滿300減100': $cs = new CashReturn(300, 100); break; case '打折': $cs = new CashRebate(0.8); break; } $this->cs = $cs; } public function getResult($money) { return $this->cs->acceptCash($money); } } // 客戶端實現 function shop($type, $money) { $cs = new CashContext($type); $res = $cs->getResult($money); return $res; } $res = shop('滿300減100', 600); echo $res; /** * 此處將策略模式與簡單工廠模式的結合使用分別於策略模式,簡單工廠模式進行比對 * * 與簡單工廠模式比對:其實就是增長了一個地方 getResult這個方法,而這個方法就是策略模式的使用,就是使用這個方法,將客戶端與實際的 * 算法類進行了隔離,封裝了變化(算法),下降了耦合性。我客戶端只讓定你這個CashContext類中的這個方法啊就能夠了,和你沒有其餘任何的關聯 * 對於不一樣的算法來講,我編寫個人算法就行了,只要我測試個人算法接受正常的參數時能夠正常運行,那就能夠了 * * 與策略模式比對:將判斷實例化哪一個類放到工廠模式的方法中進行,客戶端須要作的只是傳遞參數便可,工廠方法會根據具體的參數判斷出該實例化哪一個類 * 這樣也大大下降了服務端與客戶端的耦合性 */