zoukankan      html  css  js  c++  java
  • 案例分析:策略模式

    一、设计模式

      设计模式可以分为三类:

      创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

      结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

      行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

      用图片描述如下所示:(图片来自网络)

      

    二、策略模式

    1. 什么是策略模式

      策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理,最终可以实现解决多重if判断问题。

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

      定义策略接口->实现不同的策略类->利用多态或其他方式调用策略。

    2. 策略模式优缺点

      优点:算法可以自由切换(高层屏蔽算法,角色自由切换) 避免使用多重条件判断(如果算法过多就会出现很多种相同的判断,很难维护) 扩展性好(可自由添加取消算法 而不影响整个功能)。

      缺点:策略类数量增多(每一个策略类复用性很小,如果需要增加算法,就只能新增类) 所有的策略类都需要对外暴露(使用的人必须了解使用策略,这个就需要其它模式来补充,比如工厂模式、代理模式)。

    3. 策略模式实例说明

      我们以数组输出为例。

      数组的输出有序列化输出、JSON字符串输出和数组格式输出等方式。每种输出方式都可以独立封装起来,作为一个策略。

      应用时,如要把数组保存到数据库中,可以用序列化方式输出。要提供给APP作接口,可以用JSON字符串输出。其他程序调用,则直接输出数组格式。

    3.1 无设计模式情况下存在的问题

      在没有设计模式的情况,我们用一个类集中处理数组输出,如下:

     1 /**
     2  * 根据给定类型,将数组转换后输出
     3  */
     4 class Output
     5 {
     6     public function render($array, $type = '')
     7     {
     8         if ($type === 'serialize') {
     9             return serialize($array);
    10         } elseif ($type === 'json') {
    11             return json_encode($array);
    12         } else {
    13             return $array;
    14         }
    15     }
    16 }

      客户端直接使用这个类来处理数组,就能达到效果:

     1 /**
     2  * 客户端代码
     3  */
     4 $test = ['a', 'b', 'c'];
     5 
     6 // 实例化输出类
     7 $output = new Output();
     8 
     9 // 直接返回数组
    10 $data = $output->render($test, 'array');
    11 
    12 // 返回JSON字符串
    13 $data = $output->render($test, 'json');

      这种方法的优点是简单、快捷,在小方案中使用非常合适。

      但是,如果是一个复杂方案,包括大量的处理逻辑需要封装,或者处理方式变动较大,则就显得混乱。当需要添加一种算法,就必须修改Output类,影响原有代码,可扩展性差。如果输出方式很多,if-else或switch-case语句也会很多,代码混乱难以维护。

    3.2 使用策略模式解决问题

      首先,定义一系列的策略类,它们独立封装,并且遵循统一的接口。
      以后的维护过程中,下面的代码都不需修改了。如果需要增加输出方式,重新建一个类就可以了。
     1 /**
     2  * 策略接口
     3  */
     4 interface OutputStrategy
     5 {
     6     public function render($array);
     7 }
     8 
     9 /**
    10  * 策略类1:返回序列化字符串
    11  */
    12 class SerializeStrategy implements OutputStrategy
    13 {
    14     public function render($array)
    15     {
    16         return serialize($array);
    17     }
    18 }
    19 
    20 /**
    21  * 策略类2:返回JSON编码后的字符串
    22  */
    23 class JsonStrategy implements OutputStrategy
    24 {
    25     public function render($array)
    26     {
    27         return json_encode($array);
    28     }
    29 }
    30 
    31 /**
    32  * 策略类3:直接返回数组
    33  */
    34 class ArrayStrategy implements OutputStrategy
    35 {
    36     public function render($array)
    37     {
    38         return $array;
    39     }
    40 }

      环境类:环境角色用来管理策略,实现不同策略的切换功能。同样,一旦写好,环境角色类以后也不需要修改了。

     1 /**
     2  * 环境角色类
     3  */
     4 class Output
     5 {
     6     private $outputStrategy;
     7 
     8     // 传入的参数必须是策略接口的子类或子类的实例
     9     public function __construct(OutputStrategy $outputStrategy)
    10     {
    11         $this->outputStrategy = $outputStrategy;
    12     }
    13 
    14     public function renderOutput($array)
    15     {
    16         return $this->outputStrategy->render($array);
    17     }
    18 }

      客户端代码:在客户端中,策略模式通过给予不同的具体策略,来获取不同的结果。对于较为复杂的业务逻辑显得更为直观,扩展也更为方便。

     1 /**
     2  * 客户端代码
     3  */
     4 $test = ['a', 'b', 'c'];
     5 
     6 // 需要返回数组
     7 $output = new Output(new ArrayStrategy());
     8 $data = $output->renderOutput($test);
     9 
    10 // 需要返回JSON
    11 $output = new Output(new JsonStrategy());
    12 $data = $output->renderOutput($test);

    3.3 特点分析:

      策略模式主要用来分离算法,根据相同的行为抽象来做不同的具体策略实现。策略模式结构清晰明了、使用简单直观。并且耦合度相对而言较低,扩展方便。同时操作封装也更为彻底,数据更为安全。

      当然策略模式也有缺点,就是随着策略的增加,子类也会变得繁多。但缺点并不会影响系统运行,所以在复杂业务中应该考虑使用。

    4. github版本库URL

      https://github.com/happyyouli/Strategy-mode

  • 相关阅读:
    mysql数据库
    Mysql之sql语句操作
    mysql修改root密码的多种方法
    kvm虚拟化
    清华AIOps算法:KPI聚类
    有点扯的预测方法
    内网安全运营的逻辑体系架构
    SpringBoot定时消费Kafka消息
    kafka的consumer消费能力很低的情况下的处理方案
    Kafka_Kafka 消费者 偏移量 与 积压 查询脚本 kafka-consumer-groups.sh
  • 原文地址:https://www.cnblogs.com/happyyouli/p/12007929.html
Copyright © 2011-2022 走看看