你还在写if/else/switch这种满屏的判断逻辑吗?stackmanager在开发者的代码中见过太多这样的低级代码,实在是太low了,难以维护。本文栈长将教你如何使用策略模式干掉if/else/switch,让你的代码更优雅。什么是策略模式?比如一个对象的某个行为在不同的场景下有不同的实现方法,那么可以将这些实现方法定义为一组策略,每个实现类对应一个策略,在不同的场景下使用。实现类,策略可以自由切换。策略模式的结构图如下:策略模式需要一个策略接口,不同的策略实现不同的实现类。在特定的业务环境下,只持有策略接口,可以根据不同的场景使用不同的实现类。针对接口而不是实现编程。策略模式的优点:1.摆脱繁琐的if和switch判断逻辑;2、代码优雅,可重用,可读性好;3、遵循开闭原则,扩展性好,维护方便;策略模式的缺点:11.如果策略很多,会造成策略类的膨胀;2、用户必须清楚所有策略类及其用途;策略模式其实就是一个实际的例子,XX公司是做支付的,根据不同的客户类型会有不同的支付方式和支付产品,比如:信用卡,本地支付,本地支付在国内也有微信支付,支付宝、云闪付等第三方支付公司。这时候,策略模型就派上用场了。传统的if/else/switch等判断写法大家都可以写,这里就不贴代码了,直接看看策略模式是怎么玩的吧!1.定义一个策略接口定义一个策略接口,所有支付方式的接口。策略接口:/***支付接口*@author:栈长*@from:公众号Java技术栈*/publicinterfaceIPayment{/***payment*@paramorder*@return*/PayResultpay(Orderorder);}订单信息Class:/***订单信息*@author:栈长*@from:公众号Java技术栈*/@DatapublicclassOrder{/***金额*/privateintamount;/***支付类型*/privateStringpaymentType;}return结果类:/***@author:栈长*@from:公众号Java技术栈*/@Data@AllArgsConstructorpublicclassPayResult{/***支付结果*/privateStringresult;}2.定义各种策略,定义各种支付策略,微信支付、支付宝、云闪付等支付实现类都实现了该接口。微信支付实现:/***微信支付*@author:Stackleader*@from:公众号Java技术栈*/@Service("WechatPay")publicclassWechatPayimplementsIPayment{@OverridepublicPayResultpay(Orderorder){returnnewPayResult("WechatPaysuccess");}}支付宝实现:/***Alipay*@author:Stackleader*@from:公众号Java技术栈*/@Service("Alipay")publicclassAlipayimplementsIPayment{@OverridepublicPayResultpay(Orderorder){returnnewPayResult("支付宝支付成功");}}云闪付实现:/***银联云闪付*@author:StackManager*@from:公众号Java技术栈*/@Service("UnionPay")publicclassUnionPayimplementsIPayment{@OverridepublicPayResultpay(Orderorder){returnnewPayResult("UnionQuickPaypaymentissuccessful");}}这里我使用@Service注解为所有的支付方式生成bean,放到SpringBean容器中。使用该策略时,无需使用新的支付对象。可以直接使用Bean,更贴近业务。Spring的基础教程就不介绍了,大家可以关注公众号Java技术栈,回复:spring,历史教程我已经整理好了。3.使用策略有些文章使用枚举和HashMap,根据策略名映射策略实现类。这个没有问题,但是在使用Spring框架的项目中还是有点多余。可以充分发挥Spring框架的优势。使用Bean名称可以找到对应的策略实现类。参考示例代码如下:/***支付服务*@author:stacklength*@from:公众号Java技术栈*/@RestControllerpublicclassPayService{@AutowiredprivateApplicationContextapplicationContext;/***支付接口*@paramamount*@parampaymentType*@return*/@RequestMapping("/pay")publicPayResultpay(@RequestParam("amount")intamount,@RequestParam("paymentType")StringpaymentType){Orderorder=newOrder();order.setAmount(amount);order.setPaymentType(paymentType);//根据支付类型,获取对应的策略beanIPaymentpayment=applicationContext.getBean(order.getPaymentType(),IPayment.class);//开始支付PayResultpayResult=payment.pay(order);returnpayResult;}}看示例代码,我并没有像策略模式的结构图中那样,新建一个Context类来持有策略接口。这就是标准的策略模式。其实原理是一样的。关键是如何投策略。测试一下:http://localhost:8080/pay?amount=8800&paymentType=WechatPay测试OK,传入不同的支付方式会调用不同的策略。本教程所有实战源码已上传到本仓库:https://github.com/javastacks/javastack策略模式在JDK中的应用知道了策略模式的使用方法,我们来看看JDK在哪些地方使用了策略模式。1.线程池中的拒绝策略在线程池的构建中有一个拒绝策略参数,默认就是默认的拒绝策略:其实这是一个策略接口:下面是拒绝策略的几种实现:image-20210329161322406创建线程池时,可以传入不同的拒绝策略,这是JDK中策略模式的经典实现。2.Comparator策略接口Comparator在JDK中被广泛使用:策略接口是可以的,但是策略需要开发者来决定。我们熟悉集合排序。不同的排序规则其实是不同的策略:这种策略模式使用函数式编程接口,比较规则可以使用匿名内部类或者Lambda表达式来完成。不需要为每个规则类都定义一个实现,从而省略了大量的策略类。这种策略模式可能隐藏得很深,但它也是JDK中经典策略模式的应用。不仅限于这两个,其实还有更多,你还知道什么吗?欢迎留言分享...所以,攻略模式就在你身边,你一直在用,只是你可能没有注意到而已。.总结使用策略模式,我们可以很容易的剔除大量的if/else,代码更加优雅,并且可以灵活扩展。就像本文的支付案例一样,后面要增加或删除多少支付方式,我们都不需要去修改现有的代码,所以不会影响现有的业务,真正做到了可扩展性和封闭性修改。当然,不可能完全杜绝if/else。不能过度设计,不能为了使用设计模式而使用设计模式,否则会适得其反。但是,我们每个程序员都需要掌握策略模式,在系统中灵活运用,才能写出更优雅、更优质的代码。本教程所有实际源码已上传至本仓库:https://github.com/javastacks/javastack本文转载自微信公众号《Java技术栈》,可通过以下二维码关注代码。转载本文请联系Java技术栈公众号。
