网站建设怎样核算免费网站推广网站破解版
文章目录
- 背景
- 案例
- 第一阶段 萌芽
- 第二阶段 屎上雕花
- 第三阶段 策略+工厂模式重构
- 第四阶段 优化
- 总结
背景
大家好,我是大表哥laker。今天,我要和大家分享一篇关于如何使用策略模式和工厂模式消除If Else耦合问题的文章。这个方法能够让你的代码更加优美、简洁和易于维护。
-
在团队中,我们都希望成为一个编码能力比较牛的人,给leader一个眼前一亮的代码。
-
在面试中,也想给面试官讲出项目中的亮点,凸显自己的价值。
-
在开发中,大家都不想
屎上雕花
,遇到代码难以维护的问题,一个小的业务改动都需要改动一大坨代码,加班加点也难以解决问题。
老表们,因此,今天我分享这篇文章,希望能够帮助大家解决这些问题,让你在编写代码时更加高效,少加班,多点时间享受生活。
案例
在用户支付模块中,不同的支付方式有着不同的实现方式,例如微信支付、支付宝支付、银联支付等,用户可以自由选择支付方式去支付。在代码实现中,常常会使用大量的 If Else 语句来判断用户选择的支付方式,并根据不同的支付方式调用不同的处理逻辑。
第一阶段 萌芽
项目刚开始阶段,我们只接入了支付宝和微信支付,此时支付模块代码如下:
@Service
public class PaymentService {@Autowiredprivate AliPayService aliPayService;@Autowiredprivate WeChatPayService weChatPayService;public String pay(String payType,PayRequest request) {if ("aliPay".equals(payType)) {return aliPayService.pay(request);} else if ("weChatPay".equals(payType)) {return weChatPayService.pay(request);} // 不支持的支付方式,抛出异常throw new RuntimeException("Unsupported pay type: " + payType);}
}
此时这种写法是没问题的,也符合当前的状态。
第二阶段 屎上雕花
后来随着业务拓展的不错,用户量变大,我们又需要支持其他支付方式,例如银联支付和汇付天下支付等,核心主干代码修改如下:
@Service
public class PaymentService {@Autowiredprivate AliPayService aliPayService;@Autowiredprivate WeChatPayService weChatPayService;@Autowiredprivate UnionPayService unionPayService;@Autowiredprivate AdaPayService adaPayService;public String pay(String payType,PayRequest request) {if ("aliPay".equals(payType)) {return aliPayService.pay(request);} else if ("weChatPay".equals(payType)) {return weChatPayService.pay(request);// 👉👉👉👉👉👉 改动这里的核心主干代码} else if ("unionPay".equals(payType)) {return unionPayService.pay(request);} else if ("adaPay".equals(payType)) {return adaPayService.pay(request);} // 👉👉👉👉👉👉 改动这里的核心主干代码// 不支持的支付方式,抛出异常throw new RuntimeException("Unsupported pay type: " + payType);}
}
这个时候如果你不去重构而是沿着这种方式继续写代码就会有隐患了,此时我们就开始“屎上雕花”。
这种实现方式会导致代码可维护性差、代码复杂度高,同时也会增加代码修改的难度。
重点!重点!重点!
这样写有什么问题呢?
1.可以预见,随着业务量增长,我们肯定还会增加其他方式的支付,那么还需要直接修改主干代码,而我们提倡代码应该是对修改封闭的。
2.支付模块与具体的支付方式高度耦合,例如微信支付需要增加什么参数,我们还是需要直接修改主干代码,这导致接口的改变将直接影响到代码的组织,使得代码的可维护性降低。
第三阶段 策略+工厂模式重构
我们要进行重构,以实现在现在和未来的扩展时,不会修改主干代码,这里我们将使用策略模式+工厂模式来解决此问题,实现代码更易读、更易扩展。
第一步 首先我们定义了一个PayStrategy接口,并在接口中定义了一个pay()方法,它将接收一个PayRequest对象并返回一个字符串。
public interface PayStrategy {String pay(PayRequest request);
}
第二步 接下来,我们需要为每个具体策略实现创建一个实现类。
@Component("aliPay")
public class AliPayStrategy implements PayStrategy {@Overridepublic String pay(PayRequest request) {// 具体的支付逻辑return "使用支付宝支付成功";}
}
@Component("weChatPay")
public class WeChatPayStrategy implements PayStrategy {@Overridepublic String pay(PayRequest request) {// 具体的支付逻辑return "使用微信支付成功";}
}
@Component("unionPay")
public class UnionPayStrategy implements PayStrategy {@Overridepublic String pay(PayRequest request) {// 具体的支付逻辑return "使用银联支付成功";}
}
@Component("adaPay")
public class AdaPayStrategy implements PayStrategy {@Overridepublic String pay(PayRequest request) {// 具体的支付逻辑return "使用汇付天下支付成功";}
}
第三步 我们需要定义一个工厂类来生产具体策略实现对象。这里我们使用了Spring的@Autowired
注解来自动注入所有实现了PayStrategy
接口的类,然后根据不同的支付方式返回对应的实现类:
@Component
public class PaymentFactory {@Autowiredprivate 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()
方法进行支付。
@Service
public class PaymentService {@Autowiredprivate 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
接口的类即可。
以增加农业银行卡支付为例,我们的修改点仅仅是添加了一个如下的类即可。
这里可以看到当我们有新的支付方式加入时,你是增加新的类而不是修改原有的类。
@Component("NYBankPay")
public class NYBankPayStrategy implements PayStrategy {@Overridepublic String pay(PayRequest request) {// 具体的支付逻辑return "使用农业银行支付成功";}
}
第四阶段 优化
为了更方便地管理支付方式,我们可以使用枚举类PaymentTypeEnum
,其中包含了所有的支付方式,如:支付宝、微信支付、银联支付等。
例如,我们可以通过如下方式定义PaymentTypeEnum
枚举类:
public enum PaymentTypeEnum {ALIPAY("aliPay"),WECHAT_PAY("wechatPay"),UNION_PAY("unionPay");private String name;PaymentTypeEnum(String name) {this.name = name;}public static PaymentTypeEnum getPaymentType(String name){for (PaymentTypeEnum paymentTypeEnum : values()) {if (paymentTypeEnum.name.equals(name)) {return paymentTypeEnum;}}throw new RuntimeException("Unsupported pay type: " + name);}public String getName() {return name;}
}
然后,在我们的支付服务中,我们可以通过获取支付请求中的支付方式枚举,来决定使用哪一种支付方式,例如:
@Service
public class PaymentService {@Autowiredprivate PaymentFactory paymentFactory;// 限定参数 PaymentTypeEnum.getPaymentType(payType)public String pay(PaymentTypeEnum payType, PayRequest request) {PayStrategy payStrategy = paymentFactory.getPayStrategy(payType);return payStrategy.pay(request);}
}
通过这种方式,我们可以非常方便地添加、管理、切换不同的支付方式,使得我们的代码更加灵活、可扩展。
其他相关代码修改如下:
// 新增抽象策略类用于实现每个具体实现类的具体支付枚举类型
public abstract class AbstractPaymentStrategy implements PayStrategy{public abstract PaymentTypeEnum paymentType();
}
// 对应修改具体支付实现类
@Component
public class AliPayStrategy extends AbstractPaymentStrategy {@Overridepublic String pay(PayRequest request) {// 具体的支付逻辑return "使用支付宝支付成功";}// 这里代表这个实现类是aliPay类型支付@Overridepublic PaymentTypeEnum paymentType() {return PaymentTypeEnum.ALIPAY;}
}@Component
public class WeChatPayStrategy extends AbstractPaymentStrategy {@Overridepublic String pay(PayRequest request) {// 具体的支付逻辑return "使用微信支付成功";}@Overridepublic PaymentTypeEnum paymentType() {return PaymentTypeEnum.WECHAT_PAY;}
}@Component
public class PaymentFactory {private final Map<PaymentTypeEnum, PayStrategy> payStrategyMap = new HashMap<>();// 通过这种方式来实现工厂注册@Autowiredpublic PaymentFactory(List<AbstractPaymentStrategy> payStrategyList) {payStrategyList.forEach(payStrategy -> payStrategyMap.put(payStrategy.paymentType(), payStrategy));}public PayStrategy getPayStrategy(PaymentTypeEnum payType) {PayStrategy payStrategy = payStrategyMap.get(payType);if (payStrategy == null) {throw new RuntimeException("Unsupported pay type: " + payType);}return payStrategy;}
}
总结
当使用if-else或switch语句进行复杂条件判断时,代码会变得难以阅读和维护。这时,使用策略模式和工厂模式可以有效消除条件判断语句,使代码更加优美、简洁、易于维护。
当你coding时碰到if-else或switch语句,你就要想一想能不能用策略模式和工厂模式来优化它
使用策略模式和工厂模式的场景包括选择算法、支付方式、优惠方式、根据类型调用不同的系统等。
策略模式和工厂模式的优点包括扩展性好、符合开闭原则、符合单一职责原则、可读性好、便于维护、避免多层判断等。
然而缺点是当策略增多时,策略类的数量也会增加,对于新手读代码不友好,过度使用设计模式也是很危险的。
注意没有银弹 没有银弹 使用设计模式是为了更好地解决业务问题,而不是为了设计模式而使用设计模式。过度设计同样是不可取的。