Php设计模式之【策略模式Strategy Pattern】

【案例】

黑枣游戏公司开发小鸡快跑的游戏,小鸡从鸡窝开跑,狂奔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:翻译的是狗屁水平)

******************转载请注明来源 ***************


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值