「设计模式(一) - 策略模式」

「设计模式(一) - 策略模式」

一、从if-else说起

代码中if-else的出现频率不必多说,几乎的逻辑实现都离不这个组合。但是带来了方便的同时,也带来了多重嵌套代码块。套用重构的一句话,这些都是代码的坏味道。过多的条件判断必然增加了系统不稳定性,同时也给扩展带来了不便因素。当然优化的方式多种多样,策略模式Strategy仅仅只是其中简单的一种。

二、策略模式 Strategy

行为模式的一种,定义了一系列平行的算法,将实现与责任相分离并加以封装,当然各个策略之间是可以相互转化的。由客户端决定使用何种策略,由于策略之间的独立,为系统提供了很好的扩展性。可以理解为相同行为不同实现的组合。

三、组成部分
  • 抽象的策略(Strategy)类:公共的策略接口strategy,派生出不同的实现算法(行为是相同的),当然这个抽象的策略一般是接口,也有情况下是抽象类(具有公共的主体)。

  • 具体实现(Concrete Strategy):策略接口或者策略抽象类的具体实现类。

  • 上下文(Context):分两种情况,一种是客户端本身,另一种情况则是持有策略的引用。

  • 结构图:


    图片来自网络.png
四、简单的代码实现
1.设计一个数据加密的系统

数据加密的方式有很多种,AES、DES、RSA等等。加密的方式多种多样,但是在一个加密的系统中,加密这个行为是同样。而实现这个行为的方法是不同的。加密在这里是策略的抽象。

  • 定义加密策略顶层接口
/**
 * Created by Sai
 * on: 09/01/2022 01:08.
 * Description:策略接口
 */
public interface EncryptionAlgorithm {
    String encrypt(String message);
}
  • 以AES的方式进行加密-策略的具体实现
/**
 * Created by Sai
 * on: 09/01/2022 01:08.
 * Description:
 */
public class AES implements EncryptionAlgorithm {

    @Override
    public String encrypt(String message) {
        System.out.println("Encrypting message using AES");
        return "AES ---> " + " " + message;
    }
}
  • 以DES的方式进行加密
/**
 * Created by Sai
 * on: 09/01/2022 01:08.
 * Description:
 */
public class DES implements EncryptionAlgorithm {

    @Override
    public String encrypt(String message) {
        System.out.println("Encrypting message using DES");
        return "DES --->" + " " + message;
    }
}
  • 以RSA的方式进行加密
/**
 * Created by Sai
 * on: 09/01/2022 01:12.
 * Description:
 */
public class RSA implements EncryptionAlgorithm {

    @Override
    public String encrypt(String message) {
        System.out.println("Encrypting message using RSA");
        return "RSA ---> " + " " + message;
    }
}
  • 客户端持有类用类
/**
 * Created by Sai
 * on: 09/01/2022 01:15.
 * Description:
 */
public class Client {
    private final EncryptionAlgorithm encryptionAlgorithm;

    public Client(EncryptionAlgorithm encryptor) {
        this.encryptionAlgorithm = encryptor;
    }

    public void handleMessage(String message) {
        var encryptedMessage = encryptionAlgorithm.encrypt(message);
        System.out.println(encryptedMessage);
    }
}

这里客户端Client持有了策略对象,通过上下文Context设置关系,具体选择哪种策略是由客户端来作出选择。另一种则是由上下文来决定何种策略,调用顺序上是由差别的,但是影响不大。当然也是根据具体的业务来合理选择。

  • 测试用例
/**
 * Created by Sai
 * on: 09/01/2022 01:17.
 * Description:
 */
public class Demo {
    public static void show() {
        //选择AES进行加密
        var client = new Client(new AES());
        client.handleMessage("send messages...");
    }

    public static void main(String[] args) {
        show();
    }
}
2.一些思考

虽然是个简单的例子,但是也能看出策略模式的一些优缺点,即使现在需要增加一个新的加密算法;那么同样只需要实现顶层策略接口即可(同一行为的不同实现,面向接口的便利)它是易扩展的,但是并不代表着可以无限的增长。在例子中也发现了一个问题,同一时刻只有一个策略被执行,也造成了一定的维护成本。其次,客户端必须了解所有的策略(或者上下文Context),具体选择哪种策略是需要客户端来主动选择的。回想之前的开闭原则,这里其实已经暴露了具体的实现。当然瑕不掩瑜,策略模式是解决多重条件嵌套有效方式之一。

3.没有完美的设计模式

N种策略但同一时刻只有一种被用到了,多少有点浪费,以上述例子为例,其实可以考虑使用责任链模式替换。而且并不会暴露具体的内部实现,那是不是说责任链模式就比策略模式好呢?答案是否定的,考虑到加密方式的繁多性,责任链的链调用深度势必会很深。看,同样是有瑕疵的。没有完美的设计模式(不然也不会出现经典的23种)。但是某种情况下,各种模式的配合可以趋于完美。学习设计模式,个人觉得还是思想的学习吧。

五、开发中的实际问题

最近开发中就遇到了类似的问题,服务端WebSocket下发通知,需要处理这个通知来控制打印机工作,根据Notify Type的不同打印不同的信息文本。而目前已经实现的只有一种type,考虑到type的扩展性,想以策略形式抽象出来。

private void processPrint(PrintMessage printMessage) {
   if (printMessage == null || CheckUtil.isEmpty(printMessage.getPrintType())) {
         return;
   }
   IFetchDataDetail fetchDataDetail;
   if (printMessage.isCondition()) {
       fetchDataDetail = new PrintXXPrintRequest();
      } else {
       fetchDataDetail = new PrintNormalPrintRequest();
   }
   fetchDataDetail.onFetchDataToPrint(printMessage);
}

public interface IFetchDataDetail {
    void onFetchDataToPrint(PrintMessage message);
}

这里的抽象出来的核心操作只有一个,尽管type是不同的,但是都是通过返回的id查询详情并且打印,那么统一的行为就是IFetchDataDetail,只有一个方法void onFetchDataToPrint(PrintMessage message)至于打印何种信息,那就是策略内部的具体实现了。

但它是策略模式吗?其实不是的,与策略模式唯一的区别是没有上下文Context,可以说是退化了的策略模式:退化成简单的面向接口编程,仅仅对多重判断做了整理优化。但接口隔离优点还是有体现的,表面上看没有上下文影响不大。可事实上,客户端的难度增加了,因此还是可以继续优化的。设计的唯一目的,不就是降低客户端的使用复杂度嘛。

六、应该什么时候用
  • 仅仅只是行为实现上的区别-同一行为不同实现。
  • 优化多重条件的嵌套问题。
  • 具体业务场景具体分析,重要的还是抽象思想的理解。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
禁止转载,如需转载请通过简信或评论联系作者。

推荐阅读更多精彩内容

  • 策略模式(Strategy Pattern)也叫做政策模式(Policy Pattern),是一种行为型模式。 一...
    l只为终点阅读 675评论 1 3
  • 二十三种设计模式 - 策略模式 策略模式简介 模式动机 完成一项任务,往往可以有多种不同的方式,每一种方式称为一个...
    JustTheSame阅读 1,869评论 2 16
  • 概念及定义 概念在完成某一功能时,有时需要根据不同环境采取不同的策略或行为。将这些不同的策略或行为(称为算法)一一...
    maxwellyue阅读 598评论 0 0
  • 策略模式 定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。将共同的行为封装成策略接口,不同策略实现类只...
    AnimoBlog阅读 279评论 0 1
  • 什么是策略模式 策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法...
    小波同学阅读 276评论 0 1