玩转策略模式

栏目: 后端 · 发布时间: 6年前

内容简介:定义了举例: 在一些外部网关,如银行网关设计时,因直连模式时会接入多个银行,这些银行的具体报文封装逻辑、解析逻辑、业务逻辑不同(多个类似行为的抽象,Context所依赖的接口

定义了 算法族 (一组行为),分别 封装 起来(封装实现),让他们之间可以 相互替换 (扩展),此模式让算法的 变化(扩展)独 立与使用算法的客户(解耦);

场景

  • Strategy描述一组概念相同却行为不同(一个接口却实现不同)的相关类;
  • Strategy的使用客户不应该知道其具体实现(解耦),避免暴露复杂的、与具体策略相关的数据结构;
  • 一个类定义多种行为,避免这些行为以if-else的形式出现在此类中,减少对实现细节的依赖;

举例: 在一些外部网关,如银行网关设计时,因直连模式时会接入多个银行,这些银行的具体报文封装逻辑、解析逻辑、业务逻辑不同( 实现ConcreteStrategy ),但其都可抽象为共用的网关处理逻辑( 接口Strategy ); 为减少调用方对实现的依赖关系、便于接入其他银行、共用代码逻辑的复用 ,可采用策略模式进行设计;

结构

  • Strategy

多个类似行为的抽象,Context所依赖的接口

  • ConcreteStrategy

Strategy的具体实现,为Context提供具体逻辑实现

  • Context

上下文(客户),一个具有多种行为的类,持有strategy引用

  • 流程描述

Context 与Strategy关系为一对多,Strategy与ConcreteStrategy关系为一对多

玩转策略模式

推荐搭配

工厂模式、模板方法

代码实现

  • 简单策略DEMO

测试代码

public class TransTest extends NnnToolsApplicationTests {

    @Autowired
    private Trans trans;
    @Test
    public void testTrans(){
        TransDO transDO = new TransDO();
        Invocation invocation = new Invocation();
        invocation.setBizType("N00001");
        invocation.setParam(transDO);
        //调用,外部对内部无感知,无依赖
        //Trans内部只依赖行为接口,不依赖实现,可动态改变其行为实现
        trans.transfer(invocation);
    }
}
复制代码

简单演示动态行为切换

/**
 * @author hanlujun
 */
@Service
public class TransImpl implements Trans {
    
    @Autowired
    private Map<String,Validator> validators;

    /**
     * 交易操作
     * @param var1
     * @return
     */
    @Override
    public Result transfer(Invocation var1) {
        //**变化的行为**
        //获取对应业务类型的校验(如权限校验、非空校验、账户校验等)
        Validator validator = validators.get(var1.getBizType());
        if(Objects.nonNull(validator)){
            //校验
            validator.validation(var1.getParam());
        }
        //执行对应业务类型的业务逻辑
        return accountOperation(var1).doTransfer(var1);
    }
    
    /**
    * 测试
    */
    public TransOperation accountOperation(Invocation var1){
        // **变化的行为**
        return SpringContextUtil.getBean(var1.getBizType(), TransOperation.class);
    }
}

复制代码
  • 进阶策略DEMO

借鉴之前老师的写法来演示并做了稍微改动,demo简单描述了策略模式是如何实现可复用、可扩展、可维护的OO思想;

另外此demo仍有很大的优化空间,需要大家发散思维;

测试代码

/**
 * 测试
 */
public class TransTest extends NnnToolsApplicationTests {
    @Autowired
    private StrategyFactory strategyFactory;

    public void testTrans(){
        Context context = strategyFactory.makeDecision("N00001");
        context.execute("N00001","{}");
    }
}


复制代码

策略接口

/**
 * 多个类似行为的抽象,Context所依赖的接口
 */
public interface IStrategy {

    Response execute(String code, String jsonBody);
}

复制代码

策略接口与具体实现结合并结合模板方法

/**
 * 多个类似行为的抽象,Context所依赖的接口,具体策略有子类实现
 */
@Slf4j
public abstract class AbstractStrategy implements IStrategy{

    @Autowired
    private Map<String, Validator> validators;

    @Override
    public Response execute(String code , String jsonBody) {
      //获取对应业务类型的校验(如权限校验、非空校验、账户校验等)
        Validator validator = validators.get(code);
        if(Objects.nonNull(validator)){
            //校验
            validator.validation(jsonBody);
        }
        //执行对应业务类型的业务逻辑
        return doTransfer(code);
    }
    
     /**
     * 具体实现由子类决定
     * @param code
     * @return
     */
    protected abstract Response doTransfer(String code);

}
复制代码

策略模式中的客户Context

/**
 * 上下文(客户),一个具有多种行为的类,持有strategy引用
 */
public class Context {

    private IStrategy strategy;

    private Context(IStrategy strategy){
        this.strategy = strategy;
    }

    public static Context getInstance(IStrategy strategy){
      return new Context(strategy);
    }

    /**
     * 执行策略
     * @param code
     * @param jsonBody
     * @return
     */
    public Response execute(String code, String jsonBody) {
        return strategy.execute(code,jsonBody);
    }
}

/**
 * 策略工厂
 */
public interface IStrategyFactory {

    Context makeDecision(String code);
}
复制代码

推荐搭配:工厂类

/**
 * 策略工厂
 */
@Component
public class StrategyFactory implements IStrategyFactory {
    @Override
    public Context makeDecision(String code) {
        String serviceName =BizTypeEnums.getServiceByCode(code);
        IStrategy strategy = SpringContextUtil.getBean(serviceName);
        return Context.getInstance(strategy);
    }
}
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

写给大忙人看的C++

写给大忙人看的C++

【美】Brian Overland(布莱恩.奥弗兰德) / 卢涛、李颖 / 电子工业出版社 / 2015-8 / 109.00

《写给大忙人看的C++》全面介绍了C++语言知识,既提供了学习C++语言最新功能的捷径,也为快速找到特定问题的答案提供了便利。《写给大忙人看的C++》简明地描述了C++核心语言和标准库中几乎所有的函数、对象和运算符,一目了然地显示了语法、结构和重要函数的信息,内容组织形式便于快速查找信息。《写给大忙人看的C++》精选了实用的例子来深入地讲解概念,还提供了富有挑战性的练习及参考答案,便于读者举一反三......一起来看看 《写给大忙人看的C++》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

html转js在线工具
html转js在线工具

html转js在线工具