设计模式之策略模式

一、背景:为什么要用到策略模式?

阿里开发规约-编程规约-控制语句-第六条 :超过 3 层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现。

普通代码示例:

if (a == 1) {
	...
} else if ( a == 2 ) {
  ...
} else if (a == 3) {
	...
} else {
	...
}

这种代码虽然写起来简单,但是很明显违反了面向对象的 2 个基本原则:

  • 单一职责原则(一个类应该只有一个发生变化的原因):因为之后修改任何一个逻辑,当前类都会被修改
  • 开闭原则(对扩展开放,对修改关闭):如果此时需要添加(删除)某个逻辑,那么不可避免的要修改原来的代码

因为违反了以上两个原则,尤其是当 if-else 块中的代码量比较大时,后续代码的扩展和维护就会逐渐变得非常困难且容易出错,使用卫语句也同样避免不了以上两个问题。因此根据我的经验,得出一个我个人认为比较好的实践:

  • if-else 不超过 2 层,块中代码 1~5 行,直接写到块中,否则封装为方法
  • if-else 超过 2 层,但块中的代码不超过 3 行,尽量使用卫语句
if (a == 1) {
	...
}
if (a == 2) {
	...
}
if (a == 3){
	...
}
  • if-else 超过 2 层,且块中代码超过 3 行,尽量使用策略模式

二、策略模式如何实现
  • 定义策略接口
/**
 * @author zheyue
 * @date 2021-09-26 11:07:29
 */
public interface StrategyPatternService {

    /**
     * 根据具体的ActionName执行具体的Action
     * @return
     */
    String getActionName();

    /**
     * 执行的具体的action
     */
    void doAction();

}
  • 相关策略实现
/**
 * @author zheyue
 * @date 2021/9/26
 **/
@Slf4j
@Service
public class AlertActionServiceImpl  implements StrategyPatternService{

    @Override
    public String getActionName() {
        return "alert";
    }

    @Override
    public void doAction() {
        // 执行具体的Action
        log.warn("alert!");

    }
}

/**
 * @author zheyue
 * @date 2021/9/26
 **/
@Slf4j
@Service
public class DeleteActionServiceImpl implements StrategyPatternService{
    @Override
    public String getActionName() {
        return "delete";
    }

    @Override
    public void doAction() {
        log.warn("delete!");
    }
}
/**
 * @author zheyue
 * @date 2021/9/26
 **/
@Slf4j
@Service
public class InsertActionServiceImpl implements StrategyPatternService{
    @Override
    public String getActionName() {
        return "insert";
    }

    @Override
    public void doAction() {
        log.warn("insert");
    }
}
  • 借助Spring来完成注入
/**
 * @author zheyue
 * @date 2021/9/26
 **/
@Component
public class StrategyPatternAdapter implements ApplicationContextAware {

    /**
     * 根据ActionName将具体的Action存放到Map中
     */
    private Map<String,StrategyPatternService> strategyPatternMap = new HashMap<>();
    
    public StrategyPatternService getStrategyService(String actionName){
        return strategyPatternMap.get(actionName);
    }
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, StrategyPatternService> strategyServiceMap = applicationContext.getBeansOfType(StrategyPatternService.class);
        
        strategyServiceMap.values().forEach(strategyPatternService -> {
            strategyPatternMap.put(strategyPatternService.getActionName(), strategyPatternService);
        });
    }
}
  • 应用(这个为了方便测试,我写到了controller,大家在应用的过程中,根据自己的情况放到具体的业务处理层)
@Resource
private StrategyPatternAdapter strategyPatternAdapter;

@RequestMapping("/")
public void testStrategy() {
    List<String> actionList = Lists.newArrayList("insert", "alert");

    actionList.stream().forEach(actionName -> {
        StrategyPatternService strategyService = strategyPatternAdapter.getStrategyService(actionName);
        if (strategyService != null) {
            strategyService.doAction();
        }
    });
}
  • 执行结果
    在这里插入图片描述

  • 如何有新的策略,只需要继承策略接口,完成具体的策略实现,此时不需要修改任何代码,因为Spring会通过ApplicationContext帮助我们自动完成注入实现。

三、拓展

如果我想顺序的执行各个Action,该如何做到呢?

  • 策略接口新增排序的标识
/**
 * @author zheyue
 * @date 2021-09-26 11:07:29
 */
public interface StrategyPatternService {

    /**
     * 根据具体的ActionName执行具体的Action
     * @return
     */
    String getActionName();

    /**
     * 执行的具体的action
     */
    void doAction();

    /**
     * 条件优先级,数字越低,优先级越高
     * @return
     */
    int priority();

}

● 具体的Action实现这个方法,自定义优先级

/**
 * @author zheyue
 * @date 2021/9/26
 **/
@Slf4j
@Service
public class AlertActionServiceImpl  implements StrategyPatternService{

    @Override
    public String getActionName() {
        return "alert";
    }

    @Override
    public void doAction() {
        // 执行具体的Action
        log.warn("alert!");

    }

    @Override
    public int priority() {
        return 1;
    }
}
/**
 * @author zheyue
 * @date 2021/9/26
 **/
@Slf4j
@Service
public class InsertActionServiceImpl implements StrategyPatternService{
    @Override
    public String getActionName() {
        return "insert";
    }

    @Override
    public void doAction() {
        log.warn("insert");
    }

    @Override
    public int priority() {
        return 5;
    }
}
/**
 * @author zheyue
 * @date 2021/9/26
 **/
@Slf4j
@Service
public class DeleteActionServiceImpl implements StrategyPatternService{
    @Override
    public String getActionName() {
        return "delete";
    }

    @Override
    public void doAction() {
        log.warn("delete!");
    }

    @Override
    public int priority() {
        return 10;
    }
}

● Adapter作如下修改

public List<StrategyPatternService> strategyPatternServiceList;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    Map<String, StrategyPatternService> strategyServiceMap = applicationContext.getBeansOfType(StrategyPatternService.class);
    strategyPatternServiceList = strategyServiceMap.values()
        .stream()
        .sorted(Comparator.comparing(StrategyPatternService::priority))
        .collect(Collectors.toList());
}

/**
     * 执行具体的Action
     */
public void doAction(){
    for (StrategyPatternService strategyPatternService : strategyPatternServiceList) {
        strategyPatternService.doAction();
    }
}
  • 执行结果在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值