00 策略模式与if else

    技术2026-04-04  8

    文章目录

    1 策略模式是如何业务逻辑代码结构的?2 杀鸡焉用牛刀?条件分支结构场景需要用到策略模式?3 真实业务场景问题的解决思路

    原文:链接

    1 策略模式是如何业务逻辑代码结构的?

    首先,对于策略模式,其定义为一个类的行为或其算法可以在运行是更改。通俗来讲,就是运使程序时,给一个类的方法传不同的"key",此方法会执行不同的业务逻辑。由此我们最先想到的就是条件分支结构。那么既然条件分支结构就能够轻松实现,为什么会有策略模式的出现呢?策略模式又优化了什么呢?

    策略模式的核心思想与条件分支结构如出一辙,根据不同的key找到不同的业务逻辑。但是实际上不仅仅如此,策略模式就是在代码结构上调整,用接口+实现类+分派逻辑来提高代码结构的可维护性。 总之,即使使用了策略模式,需要写的业务逻辑一样要写,到逻辑分派的时候,还是变相的条件分支结构。但是它的优点是抽象出了接口,将业务逻辑封装成了一个个的实现类,任意的替换。在复杂场景(即业务逻辑较多)时比直接使用条件分支结构更易维护。

    2 杀鸡焉用牛刀?条件分支结构场景需要用到策略模式?

    有些开发场景中,我们的业务逻辑就那么几行,使用策略模式却需要一大堆类的定义,检查具体的业务逻辑还要去不同的类中,让人觉得很烦。所以策略模式就有以下缺点: (1)策略类会增多; (2)业务逻辑分散到各个实现类中,而且没有一个地方可以俯视整个业务逻辑。

    因此,有人提出了以下方法来解决传统策略模式的缺点。 范例:优化传统策略模式 (1)为了简单演示这个思路,代码用String类型来模拟一个业务BO |————getCheckResult()为传统做法; |————getCheckResultSuper()则事先在Map中定义好了“判断条件”与“业务逻辑”的映射关系,详见代码注释。

    /** 某个业务服务类 */ public class BizService{ /** 传统的if else解决方法 当每个业务逻辑有3、4行时,用传统的策略模式不值得,直接的if else又显得不易读 */ public String getCheckResult(String order){ if("proof1".equals(order)){ return "run service logic 1"; } else if("proof2".equals(order)){ return "run service logic 2"; }else if("proof3".equals(order)){ return "run service logic 2"; }else if("proof4".equals(order)){ return "run service logic 2"; }else if("proof5".equals(order)){ return "run service logic 2"; }else if("proof6".equals(order)){ return "run service logic 2"; }else if("proof7".equals(order)){ return "run service logic 2"; } return "can't solve, service error."; } /** 业务逻辑分派Map Function为函数式接口,下面代码中Function<String,String>的含义是接收一个String类型的变量,返回一个String类型的结果 */ private Map<String, Function<String,String>> checkResultDispatcher = new HashMap(); /** 初始化业务逻辑分派Map,其中value存放的时lambda表达式 */ @PostConstruct public void checkResultDispatcherInit(){ checkResultDispatcher.put("proof1", order->String.format("run service logic 1 for %s", order)); checkResultDispatcher.put("proof2", order->String.format("run service logic 2 for %s", order)); checkResultDispatcher.put("proof3", order->String.format("run service logic 3 for %s", order)); checkResultDispatcher.put("proof4", order->String.format("run service logic 4 for %s", order)); checkResultDispatcher.put("proof5", order->String.format("run service logic 5 for %s", order)); checkResultDispatcher.put("proof6", order->String.format("run service logic 6 for %s", order)); checkResultDispatcher.put("proof7", order->String.format("run service logic 7 for %s", order)); } public String getCheckResultSuper(String order){ //从逻辑分派Dispatcher中获取业务逻辑代码,result变量是一段lambda表达式 Function<String,String> result = checkResultDispatcher.get(order); if(result != null){ //执行这段表达式获得String类型的结果 return result.apply(order); } return "can't solve, service error."; } }

    好处很直观: (1)在一段代码里直观的看到“判断条件”与业务逻辑的映射关系; (2)不需要单独定义接口与实现类,直接使用现有的函数式接口,而实现类直接就是业务代码本身。

    不好的点: (1)需要团队对lambda表达式有所了解。

    3 真实业务场景问题的解决思路

    有人说,我的判断条件有多个,而且很复杂,之前的例子只有单个判断逻辑。那么当判断逻辑有多个的时候应当怎么办?

    解决思路:写一个判断逻辑的方法,Map的key由方法计算出

    /** 某个业务服务类 */ public class BizServiceMultiple{ /** 业务逻辑分派Map Function为函数式接口,下面代码中Function<String,String>的含义是接收一个String类型的变量,返回一个String类型的结果 */ private Map<String, Function<String,String>> checkResultDispatcher = new HashMap(); /** 初始化业务逻辑分派Map,其中value存放的时lambda表达式 */ @PostConstruct public void checkResultDispatcherMultiplyInit(){ checkResultDispatcher.put("key_order1", order->String.format("run service logic 1 for %s", order)); checkResultDispatcher.put("key_order1_order2", order->String.format("run service logic 2 for %s", order)); checkResultDispatcher.put("key_order1_order2_order3", order->String.format("run service logic 3 for %s", order)); } public String getCheckResultMultiply(String order, int level){ //写一段生成key的逻辑 String key = getDispatcherKey(order, level); Function<String,String> result = getCheckResultMultiply.get(key); if(result != null){ //执行这段表达式获得String类型的结果 return result.apply(order); } return "can't solve, service error."; } /** 判断条件方法 */ private String getDispatcherKey(String order, int level){ StringBuilder key = new StringBuilder("key"); for(int i = 1; i <= level; i++){ key.append("_" + order + i); } return key.toString(); } }

    所以只要设计好key的生成规则就可以解决了。

    但是有时候我们的业务逻辑会很长,这时候直接在checkResultDispatcherMultiplyInit()方法的Map中写会很长,这时候我们可以抽象出一个service服务专门放业务逻辑,然后在定义中调用它就好了。 范例:业务逻辑单元

    /** 提供业务逻辑单元 */ public class BizUnitService{ public String bizOne(String order){ return order + "your code 1"; } public String bizOne(String order){ return order + "your code 2"; } ... } /** 某个业务服务类 */ @Service public class BizServiceMultiple{ @Autowired private BizUnitService bizUnitService; /** 业务逻辑分派Map Function为函数式接口,下面代码中Function<String,String>的含义是接收一个String类型的变量,返回一个String类型的结果 */ private Map<String, Function<String,String>> checkResultDispatcherComplex = new HashMap(); /** 初始化业务逻辑分派Map,其中value存放的时lambda表达式 */ @PostConstruct public void checkResultDispatcherComplexInit(){ checkResultDispatcher.put("key_order1", order->bizUnitService.bizeOne(order)); checkResultDispatcher.put("key_order1_order2", order->bizUnitService.bizeTwo(order)); } public String getCheckResultComplex(String order, int level){ //写一段生成key的逻辑 String key = getDispatcherComplexKey(order, level); Function<String,String> result = getCheckResultDispatcherComplex.get(key); if(result != null){ //执行这段表达式获得String类型的结果 return result.apply(order); } return "can't solve, service error."; } /** 判断条件方法 */ private String getDispatcherComplexKey(String order, int level){ StringBuilder key = new StringBuilder("key"); for(int i = 1; i <= level; i++){ key.append("_" + order + i); } return key.toString(); } }

    总结: (1)策略模式是如何优化业务逻辑代码结构的? 抽象了出了接口,将业务逻辑封装成一个一个的实现类,任意地替换。在复杂场景(业务逻辑较多)时比直接 if else 来的好维护些。

    (2)杀鸡焉用宰牛刀?就是几个if else场景我需要用到策略模式?! 我们所不满的其实就是传统接口实现的缺点: |————策略类会很多。 |————业务逻辑分散到各个实现类中,而且没有一个地方可以俯览整个业务逻辑

    (3)有没有什么更好的代码结构来实现策略模式的吗? 针对传统策略模式的缺点,提供利用Map与函数式接口来实现的思路。

    Processed: 0.010, SQL: 9