策略模式代替老式的if-else
最近重构项目发现存在巨多的if else ,if …else if … else…这确实是我们在各种项目研发中的一个利器,但是一旦他过于多,就会使逻辑混乱,让代码的可读性大大下降,因而打算使用策略模式来代替过多的if else。
策略模式的介绍
策略模式
引入百科的解释:策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。
策略模式:顾名思义就是当要在不同的情况下做出该情况下所适用的策略,按照面向对象的是思想就是,就使用继承和多态机制,实现同一行为在不同场景下具备不同实现。
策略模式的本质:分离算法,选择实现。
主要解决
从上述的策略模式的本质中的选择实现是不是可以联想到if…else if… else…没错,在有多种算法相似的情况下,使用 if…else 或 switch…case 所带来的复杂性和臃肿性。
优缺点
优点
策略的多样性,能够自由切换
有效的避免了多重判断,提高了代码的可读性,扩展性,封装性
降低了操作难度以及错误率。
缺点
增加了开发难度,策略类数量增多,并且所要策略类都要对外开放,以便客户端访问
你还在用if else吗?
这里给大家举一个典型的例子
我们每天扫码支付,选用支付方式,选择的微信,支付宝,或者是直接银行卡支付。想必大家已经屡见不鲜了。
那我们现在我们需要做一个支付系统,通过扫描二维码对一个商户进行付款,我们可以选用我们已经绑定的支付宝账号,微信,或者所绑定的银行,直接进行支付,由于每家商户不同,可能付款的时候可能也会有一些优惠政策的不同,并且他们为外界所提供的API也会有所不同。例如,支付宝可以使用红包进行抵用,直接使用银行卡付款,每家银行可能会有不同的折扣。具体情况比较复杂,这里就不做考虑,为了为接下来的策略模式做铺垫,我们这里就简单的分为,微信支付,支付宝支付,银行卡支付,抵用券支付。
我相信很多人拿到需求后,最先考虑的写法就是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package pay; public class Example { public String selectPayWay(Integer payCode){ if (PayWayEnum.WEICHAT_PAY.equals(payCode)){ //do something return "微信支付成功" ; } else if (PayWayEnum.AL_PAY.equals(payCode)){ // do something return "支付宝支付成功" ; } else if (PayWayEnum.CARD_PAY.equals(payCode)){ // do something return "银行卡成功" ; } else if (PayWayEnum.PONIT_COUPON_PAY.equals(payCode)){ // do something return "优惠券支付成功" ; } else { return "" ; } } } |
可以看出上面四种不同的支付方式在同一个方法体内部,不利于扩展和维护,并且也不符合面向对象设计原则。对以上的代码使用策略模式进行代替,类图如下:
从 上面的UML 类图中,我们可以看到,策略模式 主要包含三种角色:
- 上下文角色(Context):用来操作策略的上下文环境,屏蔽高层模块(客户端)对策略,算法的直接访问,封装可能存在的变化;
- 抽象策略角色(Strategy):规定策略或算法的行为;
- 具体策略角色(ConcreteStrategy):具体的策略或算法实现;
java代码实现具体如下
第一步 首先我们定义了一个PayStrategy接口,并在接口中定义了一个pay()方法,它将接收一个PayRequest对象并返回一个字符串。
1 2 | package strategy; public interface PayStrategy { String pay(PayRequest request); } |
第二步 接下来,我们需要为每个具体策略实现创建一个实现类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | @Component ( "aliPay" ) public class AliPayStrategy implements PayStrategy { @Override public String pay(PayRequest request) { // 具体的支付逻辑 return "使用支付宝支付成功" ; } } @Component ( "weChatPay" ) public class WeChatPayStrategy implements PayStrategy { @Override public String pay(PayRequest request) { // 具体的支付逻辑 return "使用微信支付成功" ; } } @Component ( "unionPay" ) public class UnionPayStrategy implements PayStrategy { @Override public String pay(PayRequest request) { // 具体的支付逻辑 return "使用银联支付成功" ; } } @Component ( "adaPay" ) public class AdaPayStrategy implements PayStrategy { @Override public String pay(PayRequest request) { // 具体的支付逻辑 return "使用汇付天下支付成功" ; } } |
第三步 我们需要定义一个工厂类来生产具体策略实现对象。这里我们使用了Spring的@Autowired
注解来自动注入所有实现了PayStrategy
接口的类,然后根据不同的支付方式返回对应的实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Component public class PaymentFactory { @Autowired private Map<String, PayStrategy> payStrategyMap; public PayStrategy getPayStrategy(String payType) { PayStrategy payStrategy = payStrategyMap.get(payType); if (payStrategy == null ) { throw new RuntimeException( "Unsupported pay type: " + payType); } return payStrategy; } } |
在PayFactory类中,我们使用了@Autowired注解来自动注入所有实现了PayStrategy接口的类,这样我们就可以动态地将新的支付方式添加到系统中,而无需修改工厂类的代码。然后,我们定义了一个getPayStrategy()方法,它接收一个支付方式作为参数,然后根据支付方式返回对应的实现类。
第四步 最后,我们修改PaymentService中的pay方法,用PayFactory
类来获取具体策略实现对象并调用其pay()
方法进行支付。
1 2 3 4 5 6 7 8 9 10 11 | @Service public class PaymentService { @Autowired private PaymentFactory paymentFactory; public String pay(String payType, PayRequest request) { PayStrategy payStrategy = paymentFactory.getPayStrategy(payType); return payStrategy.pay(request); } } |
在PaymentService类中,我们使用了@Autowired注解来自动注入PayFactory类的实例。然后,我们定义了一个pay()方法,它接收一个支付方式和一个PayRequest对象作为参数,然后通过PayFactory类获取对应的具体策略实现对象,并调用其pay()方法。
通过使用策略模式和工厂模式,我们成功消除了代码中的if-else语句,使得代码更加优美、简洁、易于维护。而且,当我们需要添加新的支付方式时,只需要添加一个实现了PayStrategy接口的类即可。
或者创建策略类的工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | package strategy; import pay.PayWayEnum; import strategy.paystrategy.ALPayStrategy; import strategy.paystrategy.CardPayStrategy; import strategy.paystrategy.PointCouponPayStrategy; import strategy.paystrategy.WeChatPayStrategy; import java.util.HashMap; import java.util.Map; public class StrategyFactory { private static StrategyFactory factory = new StrategyFactory(); private StrategyFactory(){} private static Map strategyMap = new HashMap<>( 16 ); static { strategyMap.put(PayWayEnum.AL_PAY.getCode(), new ALPayStrategy()); strategyMap.put(PayWayEnum.WEICHAT_PAY.getCode(), new WeChatPayStrategy()); strategyMap.put(PayWayEnum.CARD_PAY.getCode(), new CardPayStrategy()); strategyMap.put(PayWayEnum.PONIT_COUPON_PAY.getCode(), new PointCouponPayStrategy()); } public PayStrategy create(Integer payCode){ return (PayStrategy) strategyMap.get(payCode); } public static StrategyFactory getInstance(){ return factory; } } |
实现客户端
1 2 3 4 5 6 7 8 9 | package strategy; public class Client { public static void main(String[] args) { PayContext payContext = new PayContext(); System.out.println(payContext.selectPayWay( 100 )); } } |
最后在贴一个枚举类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package pay; public enum PayWayEnum { /**微信支付*/ WEICHAT_PAY( "微信支付" , 100 ), /**支付宝支付*/ AL_PAY( "支付宝支付" , 101 ), /**银行卡支付*/ CARD_PAY( "银行卡支付" , 102 ), /**点券支付*/ PONIT_COUPON_PAY( "点券支付" , 103 ); private String msg; private Integer code; PayWayEnum(String msg, Integer code) { this .msg = msg; this .code = code; } public String getMsg() { return msg; } public Integer getCode() { return code; } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南