【案例】
黑枣游戏公司开发小鸡快跑的游戏,小鸡从鸡窝开跑,狂奔100米后到达安全地带。这500米中,小鸡可以使用辅助工具,不限于鸡爪、滑板、自行车、火箭运输。
【分析OOA】
小鸡快跑游戏是使用策略模式的一个典型实例,我们分析一下小鸡快跑游戏的特征
1. 定义了一系列的算法。小鸡的狂奔包括鸡爪、滑板、自行车、火箭运输多个方式。
2. 这些算法有相同的结果或实现,它们还可以相互替换。无论使用鸡爪还是滑板狂奔,最终的结果是小鸡到达安全地带。
【设计OOD】
<UML>
<说明>
1、抽象策略角色 CrossingStrategy: 抽象策略角色定义了一个公共接口,各种不同的算法以不同的方式实现这个接口。策略类通常由一个接口或者抽象类实现
2、CrossByFoot\CrossBySkateboard\CrossByBike\CrossByRocketo为具体策略角色,实现了CrossingStrategy:定义的接口,提供具体的算法实现。
3、Chick为环境角色:持有一个策略类的引用,最终给客户端调用
【编程 OOP:
<代码>
//抽象策略角色 abstract class CrossingStrategy { public abstract function cross($distance = 0); } //具体策略角色 class CrossByFoot extends CrossingStrategy { public function cross($distance = 0) { echo "Start run by Foot:\n"; while ($distance > 0) { if ($distance % 2 == 0) { echo '/'; } else { echo '\\'; } usleep(60000); $distance--; } echo "Crossed!"; } } //具体策略角色 class CrossBySkateboard extends CrossingStrategy{ public function cross($distance = 0){ echo "Start run by BySkateboard:\n"; while($distance > 0){ echo '_'; usleep('50000'); $distance -- ; } echo "Crossed!"; } } //具体策略角色 class CrossByBike extends CrossingStrategy { public function cross($distance = 0) { echo "Start run by Bike:\n"; while ($distance > 0) { echo '*'; usleep(40000); $distance--; } echo "Crossed!"; } } //具体策略角色 class CrossByRocket extends CrossingStrategy { public function cross($distance = 0) { echo "Start run by Rocket:\n"; while ($distance > 0) { echo '='; usleep(20000); $distance--; } echo "Crossed!"; } } //环境角色 class Chick{ private $tool = null; public function useTool($type = ''){ if(empty($type)) $type = 'Foot'; if(class_exists('CrossBy'.$type)){ $toolclass = 'CrossBy'.$type; $this->tool = new $toolclass; } } public function run($distance = 100){ $time = time(); $this->tool->cross($distance); echo "Used Time:".(time()-$time)." seconds\n"; } }
【测试用例Test Case】
<代码>
class testDriver { public function run() { $chick1 = new Chick(); //使用鸡爪 $chick1->useTool('Foot'); $chick1->run(); $chick2 = new Chick(); //使用自行车 $chick2->useTool('Bike'); $chick2->run(); $chick3 = new Chick(); //使用滑板 $chick3->useTool('Skateboard'); $chick3->run(); $chick4 = new Chick(); //使用火箭 $chick4->useTool('Rocket'); $chick4->run(); } } $test = new testDriver(); $test->run();
【输出>
小结:
【适用场景】
1.如果系统需要多种算法的其中一种的时候,可以把每种算法封装成具有相同接口的策略类。
2.类的多种行为在条件语句中出现时,可以将相关分支重构到策略类中,替换条件语句
【模式实现要点】
策略模式是对算法的包装,是把使用算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:"准备一组算法,并将每一个算法封装起来,使得它们可以互换。
【优点】
1、 策略模式可以把行为和环境分割开来。环境类负责维持和查询行为类,各种算法则在具体策略类中提供。由于算法和环境独立开来,算法的增减、修改都不会影响环境和客户端。当出现新的促销折扣或现有的折扣政策出现变化时,只需要实现新的策略类,并在客户端登记即可。策略模式相当于"可插入式(Pluggable)的算法"。
2、简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。2、避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
3、遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
【缺点】
1、因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。
2、在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。(这本身没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化的减轻了客户端的压力。)
用一句话来说,就是:"准备一组算法,并将每一个算法封装起来,使得它们可以互换。
********************************************
* 作者:叶文涛
* 标题:Php设计模式之【策略模式[Strategy Pattern】
* 参考:
*《设计模式:可复用面向对象软件基础 》(美)Erich Gamma 等著
*《Head First设计模式》Eric Freeman等著
*《PHP设计模式》Aaron Saray等著,梁志敏等译(PS:翻译的是狗屁水平)
******************转载请注明来源 ***************