专栏首页gaoqin31设计模式之 策略模式

设计模式之 策略模式

策略模式属于对象行为型的设计模式

定义 :封装了一些列算法,它们之前可以相互替换,此模式使得算法的改变,不会影响到使用它们的客户端

策略模式有以下3个角色组成

抽象策略类 : 所有策略类的父类,为所支持的策略算法声明了抽象方法

具体策略类 :实现抽象策略类的方法

Context环境类 : 维护一个对Strategy对象的引用

策略模式分离了算法的定义和使用,要做到这样客户端要依赖于策略接口,而不是具体的实现所有策略类对象可以互相替换,说明具有共同的特性->行为相同

以下是PHP对上述UML的实现

<?php
/*
 *抽象策略类 
 */
abstract class Stratrgy{
    abstract function AlgorithmInterface();
}

//具体实现类A
class ConcreateStratrgyA extends Stratrgy{
    public function AlgorithmInterface() {
        echo '算法A', PHP_EOL;
    }
}

//具体实现类B
class ConcreateStratrgyB extends Stratrgy{
    public function AlgorithmInterface() {
        echo '算法B', PHP_EOL;
    }
}

//具体实现类C
class ConcreateStratrgyC extends Stratrgy{
    public function AlgorithmInterface() {
        echo '算法C', PHP_EOL;
    }
}

//上下文环境类
class Context{
    private $_strategy;
    //通过构造方法注入策略对像
    public function __construct(Stratrgy $strategy) {
        $this->_strategy = $strategy;
    }
    public function ContextInterface(){
        $this->_strategy->AlgorithmInterface();
    }
}

//客户端类
class Client{
    public static function main(){
        $context = new Context(new ConcreateStratrgyA());
        $context->ContextInterface();
        
        $context = new Context(new ConcreateStratrgyB());
        $context->ContextInterface();
        
        $context = new Context(new ConcreateStratrgyC());
        $context->ContextInterface();
    }
}
Client::main();

在实际开发中,我们项目里很多地方都用到了策略模式,这里以支付回调为栗子介绍下策略模式在我们项目中的应用。

首先所有的支付回调都是由第三方发起,行为相同,最终都是给用户发送道具并通知第三方。整个流程可以抽象为3个步骤 :验证第三方参数 ->发送道具给用户 ->返回报文给第三方,因此我们的抽象策类里可以定义3个抽象方法,另外一些公共使用的方法都可以放到抽象

策略类里,具体策略类只需要继承就可以复用。策略环境类这里做了一些改动,加入了简单工厂模式生成具体的策略对象。每种支付的参数验证,发具体的道具数,以及报文响应都不相同,具体的支付类需要实现3个抽象方法。

由微信切换成支付宝,需要增加对应的支付宝类,然后回调的时候在工厂方法传入支付宝参数即可,这样微信,支支付宝...达到了相互替换的目的,而且具体的支付宝微信类改变不会影响到回调的入口。

抽简后的代码如下:

<?php
//抽象策略类
abstract class StrategyNotify{
   //参数检查
   abstract function checkParam();
   //发送道具
   abstract function sendProp();
   //输出报文
   abstract function outputMessage();
   //支付回调状态
   protected $_status = -1;
   //第三方参数
   protected $_params = array();

   protected $_errMsg = array(
       '-1'=>'系统错误',
       '-2'=>'参数验证错误',
       '-3'=>'发送道具失败',
   );
   //通知方法
   public final function notify(){
       if(!$this->checkParam()){
           $this->_status = -2;
       }else if(!$this->sendProp()){
           $this->_status = -3;
       }else{
           $this->_status = 1;
       }
       if($this->_status != 1){
           $this->log();
       }
       $this->outputMessage();
   }
   //写日志例子
   protected function log(){
       echo isset($this->_errMsg[$this->_status]) ? $this->_errMsg[$this->_status] : '';
       echo PHP_EOL;
   }
}

//微信支付
class Weixin extends StrategyNotify{
   public function checkParam() {
       return false;
   }

   public function outputMessage() {
       if($this->_status === 1){
           die('OK');
       }else{
           die('FAIL');
       }
   }

   public function sendProp() {
       return false;
   }
}

//支付环境类
class Pay{
    private static $_notify = null;
    //策略工厂
    public static function factory($notify){
        if(class_exists($notify) && self::$_notify == null){
            self::$_notify = new $notify();
        }
        return self::$_notify;
    }
}

Pay::factory('Weixin')->notify();

总结

优点:

1.当新增策略的时候,只需要增加具体的策略类,达到了开闭原则的目的

2.分离了算法的定义和使用,使得算法可以复用

缺点

1.每增加一个策略就需要增加一个策略类(目前我们的app接近200种支付,意味着有200个子类)

2.无法在客户端同时使用两种策略(我们的支付下单,需要从多种支付依照优先级一个个去下单,直到成功为止)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 设计模式之 六大原则

    定义: 一个类承担的职责不宜过多,或者说就一个类而言,应该仅有一个引起它变化的原因

    用户3094376
  • 设计模式之 工厂模式

    简单工厂模式 : 简单工厂模式是属于创建型的设计模式,又叫做静态工厂方法模式,但不属于23种GOF设计模式,简单工厂模式是由一个工厂决定创建哪一类产品的实例,简...

    用户3094376
  • 监控线上服务的小脚本

    利用shell脚本定时扫描线上服务是否开启,发邮件到相关人的邮箱。需要安装nmap yum install nmap 。

    用户3094376
  • PHP设计模式之命令模式

    命令模式,也称为动作或者事务模式,很多教材会用饭馆来举例。作为顾客的我们是命令的下达者,服务员是这个命令的接收者,菜单是这个实际的命令,而厨师是这个命令的执行者...

    硬核项目经理
  • Spring5以来注册Bean的各种姿势,特别最后的纯编码注册值得尝试

    各位好,今天我们的内容是有关Spring 5以来有关注册bean的几种方式。前面两三个是比较常用的方式,最后两种是只有在特殊的场合下才会被用到和想到。我们会分别...

    ImportSource
  • Java泛型的局限和使用经验泛型的局限泛型的常用经验参考资料

    //使用泛型类 @Data @Builder @AllArgsConstructor @NoArgsConstructor public class Data...

    阿杜
  • JAVA回忆录之泛型篇

    泛型是JDK1.5版本中加入的,在没有泛型之前,从集合中读取到的每一个对象都必须进行转化。如果有人不小心插入了类型错误的对象,在运行时的转化处理就会出错。有了泛...

    静默加载
  • Thinking in Java学习杂记(第7章)

    将一个方法调用同一个方法主体连接到一起就称为“绑定”(Binding)。若在程序运行以前执行绑定,就叫做“早期绑定”。而Java中绑定的所有方法都采用后期绑定技...

    范中豪
  • JAVA-方法重载,类的封装访问权限,构造/析构方法

    通过类来生成的一个对象, 根据类生成的对象都具备相同的行为(class成员函数),但是属性(class成员变量)不一定相同.

    张诺谦
  • React Native set get 方法

    就可以直接 model.testData = 'test'; 设置 console.log(model.testData); 获取

    onety码生

扫码关注云+社区

领取腾讯云代金券