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

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

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

六、应该什么时候用
  • 仅仅只是行为实现上的区别-同一行为不同实现。
  • 优化多重条件的嵌套问题。
  • 具体业务场景具体分析,重要的还是抽象思想的理解。

你可能感兴趣的:(「设计模式(一) - 策略模式」)