设计模式(二):策略者模式

转载请注明作者和出处//www.greatytc.com/p/fceff41be9d1

运行平台: Windows

php版本: php7.0


策略模式,简单来说,就是完成不同的的任务,却用相同的方法来实现,我们可能见过用到策略模式的地方就是php框架中,封装了针对不同数据库的方法,可是我们却都能用同一种方法调用他们,我是这么理解的,如果有什么错误的地方欢迎指正。

  • 环境角色(Context):持有一个Strategy的引用
  • 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体的策略类所需的接口
  • 具体策略(ConcreateStrategy)角色:包装了相关的算法或行为

常用英文单词:Strategy,Context
最好把设计模式常用的英文单词用熟,这样在你阅读源代码的时候有很大的帮助,往往大神写的代码注释很少,但是他们的变量名,方法名都符合规范,你看到这个单词就知道是怎么一回事,这比无用的注释好了很多


//定义一个规范,抽象策略类
abstract class Strategy{
    //小明上学的方法
    abstract function Way();
}

//骑自行车类
class BikeStrategy extends Strategy{
    public function Way()
    {
        echo "骑自行车上学咯";
    }
}

//小车类
class CarStrategy extends Strategy{
    public function Way()
    {
        echo "开车上学咯";
    }
}

//走路上学类
class WalkStrategy extends Strategy{
    public function Way()
    {
        echo "走路上学咯";
    }
}

class SchoolContext{
    private $strategy;//获取具体策略
    public function __construct(Strategy $strategy)//参数设定为继承Strategy接口的子类
    {
        $this->strategy= $strategy;
    }

    public function useRun(){
        $this->strategy->Way();
    }
}

$school = new SchoolContext(new BikeStrategy());
$school->useRun();//骑自行车上学咯
$school = new SchoolContext(new WalkStrategy());
$school->useRun();//走路上学咯

这里我们把实例化的类作为一个参数注射(依赖注入,内部方法的实现依赖于外部实例化类)进入到学校类之中,我们使用类 Strategy $strategy 限制类必须为继承Strategy接口的子类,这样可以有效防止注入大炮火箭之类乱七八糟的东西,好了,那么我们看看策略模式的一些实际应用场景。

<?php

//分享类抽象接口
abstract class ShareStrategy{
    //分享的标题
    abstract function share_title();

    //分享的作者
    abstract function share_author();

    //分享的文章
    abstract function share_content();
}

//微信分享
class WechatShareStrategy extends ShareStrategy{
    //分享的标题
    public function share_title(){
        //标题
    }

    //分享的作者
    public function share_author(){
        //作者
    }

    //分享的文章
    public function share_content(){
        //文章
    }
}

//qq分享
class QQShareStrategy extends ShareStrategy{
    //分享的标题
    public function share_title(){
        //标题
    }

    //分享的作者
    public function share_author(){
        //作者
    }

    //分享的文章
    public function share_content(){
        //文章
    }
}



class ShareContext{
    private $strategy;//保存对象
    public function __construct(ShareStrategy $strategy)//参数设定为继承Strategy接口的子类
    {
        $this->strategy = $strategy;
    }

    public function title(){
        $this->strategy->share_title();
    }
    public function author(){
        $this->strategy->share_author();
    }
    public function content(){
        $this->strategy->share_content();
    }
}

class ShareFactory{
    static public function factory($strategy){
        switch($strategy){
            case 'wechat':
                $object = new WechatShareStrategy();
                break;
            case 'qq':
                $object = new QQShareStrategy();
                break;
        }
        return $object;
    }
}

class Article{
    //分享
    public function Share(){
        $strategy = ShareFactory::factory('wechat');
        $shareContext = new ShareContext($strategy);
        $shareContext->title();//微信分享标题
        $shareContext->author();//微信分享作者
        $shareContext->content();//微信分享内容
    }
}

我们这里结合上一章所学的简单工厂实现了一个分享的简单例子,当然,简单工厂也有局限性,就是我们每次增加一个分享类,就要去工厂里增加方法,破化了类的开放封闭原则,我们可以结合类的反射来修改一下ShareFactory方法;

<?php

//分享类抽象接口
abstract class ShareStrategy{
    //分享的标题
    abstract function share_title();

    //分享的作者
    abstract function share_author();

    //分享的文章
    abstract function share_content();
}

//微信分享
class WechatShareStrategy extends ShareStrategy{
    //分享的标题
    public function share_title(){
        echo 'wechat_title'."\n";
        //标题
    }

    //分享的作者
    public function share_author(){
        echo 'wechat_author'."\n";
        //作者
    }

    //分享的文章
    public function share_content(){
        echo 'wechat_content'."\n";
        //文章
    }
}

//qq分享
class QQShareStrategy extends ShareStrategy{
    //分享的标题
    public function share_title(){
        echo 'qq_title';
        //标题
    }

    //分享的作者
    public function share_author(){
        echo 'qq_author';
        //作者
    }

    //分享的文章
    public function share_content(){
        echo 'qq_content';
        //文章
    }
}



class ShareContext{
    private $strategy;//保存对象
    public function __construct(ShareStrategy $strategy)//参数设定为继承Strategy接口的子类
    {
        $this->strategy = $strategy;
    }

    public function title(){
        $this->strategy->share_title();
    }
    public function author(){
        $this->strategy->share_author();
    }
    public function content(){
        $this->strategy->share_content();
    }
}

class ShareFactory{

//返回实例化对象
    static public function factory($strategy){
        //$strategy为类的字符串名称
        $class = new ReflectionClass($strategy);
        return $class->newInstance();
    }
}

class Article{
    //分享
    static public function Share(){
        $strategy = ShareFactory::factory('WechatShareStrategy');
        $shareContext = new ShareContext($strategy);

        $shareContext->title();//微信分享标题
        $shareContext->author();//微信分享作者
        $shareContext->content();//微信分享内容
    }
}
Article::Share();

输出结果
输出结果.png

我们通过传入类的字符串名称,来进行动态的实例化类(在框架里一般还会配合spl_autoload_register()这个自动加载类来加载实现实例化类),关于这类实例化类还需要考虑构造函数的参数等等因素,我这里比较简单的提一下,有需要的可以去百度查找一下更详细的资料,或者以后在依赖注入这一章节会配合laravle核心ioc容器来详细讲解。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。