玩转策略模式
Posted hanlujun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了玩转策略模式相关的知识,希望对你有一定的参考价值。
策略模式
源码地址
定义
定义了算法族(一组行为),分别封装起来(封装实现),让他们之间可以相互替换(扩展),此模式让算法的变化(扩展)独立与使用算法的客户(解耦);
场景
- 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);
}
}
源码地址
以上是关于玩转策略模式的主要内容,如果未能解决你的问题,请参考以下文章