<?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类中的这个方法啊就能够了,和你没有其余任何的关联 * 对于不一样的算法来讲,我编写个人算法就行了,只要我测试个人算法接受正常的参数时能够正常运行,那就能够了 * * 与策略模式比对:将判断实例化哪一个类放到工厂模式的方法中进行,客户端须要作的只是传递参数便可,工厂方法会根据具体的参数判断出该实例化哪一个类 * 这样也大大下降了服务端与客户端的耦合性 */