当前位置: 首页 > 科技观察

攻略模式——一个小计划完全可以消除多个ifelse

时间:2023-03-17 13:03:37 科技观察

本文转载自微信公众号《JavaKeeper》,作者海星。转载本文请联系JavaKeeper公众号。先在阿里的《 Java 开发手册》里发个规范吧。其他的方法我们先不讨论,主要说一下策略模型。定义策略模式(StrategyDesignPattern):封装可互换的行为,并使用委托来决定使用哪一个。策略模式是一种行为设计模式,它允许你定义一系列算法,并将每个算法放到一个单独的类中,这样算法的对象就可以相互替换。用人类的语言翻译就是:我会在运行时给这个类的方法传递不同的“钥匙”,你的方法会执行不同的业务逻辑。你尝尝,你尝尝,这不就是ifelse做的吗?我们先直观的看一下传统的多重ifelse代码。publicStringgetCheckResult(Stringtype){if("校验1".业务逻辑1";}elseif("校验2".equals(type)){return"执行业务逻辑2";}elseif("校验3".equals(type)){return"执行业务逻辑3";}elseif("检查4".equals(type)){return"执行业务逻辑4";}elseif("检查5".equals(type)){return"执行业务逻辑5";}elseif("检查6".equals(type)){return"执行业务逻辑6";}elseif("检查7".equals(type)){return"执行业务逻辑7";}elseif("校验8".equals(type)){return"执行业务逻辑8";}elseif("校验9".equals(type)){return"执行业务逻辑9";}return"不返回业务errorsintheprocessinglogic”;}这样看,如果你还觉得很清楚,想象一下这些return里面有各种复杂的业务逻辑方法~~当然,策略模式的作用不仅仅是为了避免冗长的if-else或switch分支,它还可以像模板方法模式一样提供框架扩展点等。网上有很多例子。比如不同路线的规划,不同支付方式的选择,就是典型的if-else问题,也是典型的策略模式问题。后面我们会举个栗子,先看策略模式的类图,然后进行多重判断~类图策略模式涉及三个角色:Strategy:策略接口或策略抽象类,用来约束一系列strategyalgorithms(Context使用该接口调用具体策略实现算法)ConcreateStrategy:具体策略类(实现策略接口或继承抽象策略类)Context:上下文类,持有具体策略类的实例,负责调用相关算法并应用策略模式来解决问题。解题思路的例子先来看一个最简单的策略模式demo:1、Strategy接口(定义策略)publicinterfaceStrategy{voidoperate();}2、具体算法实现publicclassConcreteStrategyAimplementsStrategy{@Overridepublicvoidoperate(){//具体算法实现System.out.println("执行业务逻辑A");}}publicclassConcreteStrategyBimplementsStrategy{@Overridepublicvoidoperate(){//具体算法实现System.out.println("执行业务逻辑B");}}3.实现contextpublicclassContext{//持有一个具体的策略对象privateStrategystrategy;//构造方法,传入具体的策略对象publicContext(Strategystrategy){this.strategy=strategy;}publicvoiddoSomething(){//调用具体的策略对象来操作策略。operate();}}4.客户端使用(使用策略)publicstaticvoidmain(String[]args){Contextcontext=newContext(newConcreteStrategyA());context.doSomething();}ps:这个策略的使用其实很死板。如果你实际使用的时候还这么写的话,if-else就大推了没有区别,所以我们一般会结合工厂类,在运行时动态决定使用哪种策略。策略模式关注的是如何选择策略,工厂模式关注的是如何创建策略。分析策略模式策略模式的作用是将具体的算法实现从具体的业务处理中分离出来,将它们实现到一个单独的算法类中,从而形成一系列的算法,并使这些算法相互替代。策略模式的重点不是如何实现算法,而是如何组织和调用这些算法,使程序结构更加灵活,具有更好的可维护性和可扩展性。实际上,各个策略算法实现的具体功能,就是原来if-else结构中的具体实现。每一个if-else语句都是一个相等的函数结构,可以说是兄弟关系。策略模式就是将每个相等的具体实现封装成一个单独的策略实现类,然后通过上下文与具体的策略类进行交互。《策略模式=实现策略接口(或抽象类)的各个策略类+上下文的逻辑赋值》策略模式的本质:分离算法,选择实现-《研磨设计模式》所以,策略模式只是一个代码结构调整,即使使用策略模式,也少不了该写的逻辑。当分配逻辑时,它只是一个伪装的if-else。而它的优化点就是将接口抽象出来,将业务逻辑一个一个封装到实现类中,任意替换。在复杂场景下(更多业务逻辑),比直接if-else更好维护和扩展。具体的策略算法谁来选择如果你手写上面的demo,你会发现这东西没有if-else那么简单,尤其是判断逻辑的时候,每个逻辑都需要构造一个context对象,比较费力。其实在策略模式中,我们可以定义由谁来选择具体的策略算法。有两种:client:使用context时,client选择,像我们上面的democontext:client不需要选择,由context决定选择具体的策略算法,可以指定优缺点在构造函数中。优点:避免多个条件语句:即避免大量的if-else扩展性更好(完全符合开闭原则):在策略模式下扩展新的策略实现很容易,不需要修改上下文,只是增加一个新的策略实现类缺点:客户必须了解每个策略的区别(这个可以通过IOC和依赖注入来解决)增加对象的数量:每个具体的策略被封装为一个类,可能有很多备选策略只适用于扁平化算法结构:策略模式中的一系列算法是相等的,即在运行时只会使用一个算法,限制了算法使用的层次,不能考虑嵌套使用,在实际使用中,它往往不是单一设计模式的应用,一般都是混合使用,而且模式的组合也不固定,需要具体问题具体分析湖。策略模式经常和其他模式结合使用,比如工厂、模板等,具体使用需要结合自己的业务。记住,不要为了使用设计模式而强求模式,也不要把简单的问题复杂化。策略模式并不是为了消除if-else而设计的,不要等同于if-else。它体现了“对修改关闭,对扩展开放”的原则。不是说看到if-else就想用策略模式去优化。业务逻辑简单,几个枚举或者几个guard语句就可以搞定的场景,不用硬套设计模式。策略模式在JDK中的应用在JDK中,Comparator比较器是一个策略接口,而我们常用的compare()方法是定义排序规则的具体策略实现。publicinterfaceComparator{intcompare(To1,To2);//...}当我们要自定义排序规则时,可以实现Comparator。这时候我们重写接口中的compare()方法,就是具体的策略类(不过这里可能是内部类)。当我们调用Arrays的排序方法sort()时,可以使用默认的排序规则,也可以使用自定义的规则。publicstaticvoidmain(String[]args){Integer[]data={4,2,7,5,1,9};Comparatorcomparator=newComparator(){@Overridepublicintcompare(Integero1,Integero2){if(o1>o2){return1;}else{return-1;}}};Arrays.sort(data,comparator);System.out.println(Arrays.toString(data));}数组sort()方法,有自定义规则按照自己的方法排序,否则按照源码逻辑。publicstaticvoidsort(T[]a,Comparatorc){if(c==null){sort(a);}else{if(LegacyMergeSort.userRequested)legacyMergeSort(a,c);elseTimSort。sort(a,0,a.length,c,null,0,0);}}另外,ThreadPoolExecutor中的拒绝策略RejectedExecutionHandler也是一个典型的策略模式,有兴趣的也可以看看源码。参考与感谢:《用 Map + 函数式接口来实现策略模式》《研磨设计模式》