【案例】
黑枣游戏公司开发小鸡快跑的游戏,小鸡从鸡窝开跑,狂奔100米后到达安全地带。这500米中,小鸡可以使用辅助工具,不限于鸡爪、滑板、自行车、火箭运输。
【分析OOA】
小鸡快跑游戏是使用策略模式的一个典型实例,我们分析一下小鸡快跑游戏的特征
1. 定义了一系列的算法。小鸡的狂奔包括鸡爪、滑板、自行车、火箭运输多个方式。
2. 这些算法有相同的结果或实现,它们还可以相互替换。无论使用鸡爪还是滑板狂奔,最终的结果是小鸡到达安全地带。
【设计OOD】
<说明>
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:翻译的是狗屁水平)
******************转载请注明来源 ***************