设计模式【策略模式】
今天不搞别的就来点素的,分享一个Java日常开发中常用的设计模式——策略模式。
在企业开发中,策略模式运用也非常广泛,用的好可以大大的提高代码的管理性,对相关算法或行为族管理一目了然。。 同时也具有更好的维护性和拓展性。
文章目录
一. 简单认识
某些类具有相同的行为或相似的算法实现,把它们更加抽象化的管理。能在运行时动态的选择相应的行为活动进行更改。他的重心不是在算法怎么实现而是管理,如何组织、调用这些算法,从而让程序结构更加灵活。这就是策略模式,属于设计模式中的行为型模式。
优缺点
优点
- 减少了冗余的代码判断 if…else… ,根据当前场景相互替换不同的算法实现,完全独立更易于维护,符合开闭原则
- 提供了管理相关算法族的办法,恰当的把公共的代码放在接口中大大减少了代码的重复。
缺点
- 项目中存在多个策略类时,存在很多不同的算法实现,提高了系统的复杂性
- 所有的策略都需要暴露
二. 撸代码
1. 首先我们需要定义抽象出来相同行为的接口
要有获取标识的方法,用于区分各种算法的实现表示唯一标识
public interface Payment {
/**
* 支付行为
*/
Result pay();
/**
* 获取支付方式
*/
List<String> getMode()
}
管理基类行为算法标识枚举
public enum PayModeEnum {
Wx,
Alipay
;
}
2. 定义策略工厂
这里要声明是Spring的组件,不然项目启动时无法执行生命周期,为成员属性赋值。
第一种: 借用构造方法让框架自动注入
@Component
public class PaymentStrategy {
// 策略类工厂容器
private static final Map<String, Payment> CONTEXT = new HashMap<>();
// 通过构造方法把策略实现注册到容器中
public PaymentStrategy(List<Payment> paymentList) {
paymentList.forEach(payment -> {
payment.getMode().forEach(mode -> {
CONTEXT.putIfAbsent(mode, payment);
});
});
}
public Result pay(PayModeEnum payModeEnum) {
Payment payment = Objects.requireNonNull(CONTEXT.get(payModeEnum.toString()));
return payment.pay();
}
}
第二种: 手动初始化从容器进行注入
@Component
public class PaymentStrategy implements InitializingBean, ApplicationContextAware {
private ApplicationContext applicationContext;
private static final Map<String, Payment> CONTEXT = new HashMap<>();
@Override
public void setApplicationContext(@NonNull ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() {
// 手动将所有实现注册到工厂容器
applicationContext.getBeansOfType(Payment.class)
.values()
.forEach(payment -> payment.getMode().forEach(mode -> CONTEXT.putIfAbsent(mode, payment)));
}
public Result pay(PayModeEnum payModeEnum) {
Payment payment = Objects.requireNonNull(CONTEXT.get(payModeEnum.toString()));
return payment.pay();
}
}
3. 基类实现行为算法
@Service
public class WxPaymentServiceImpl implements WxPaymentService, Payment {
// 指定基类的标识信息
@Override
public List<String> payMode() {
return Collections.singletonList(PayModeEnum.Wx.toString());
}
@Override
public Result pay() {
// 微信支付算法逻辑实现
//todo: ...
}
}
@Service
public class AlipayPaymentServiceImpl implements AliPayPaymentService, Payment {
// 指定基类的标识信息
@Override
public List<String> payMode() {
return Collections.singletonList(PayModeEnum.Alipay.toString());
}
@Override
public Result pay() {
// 阿里支付算法逻辑实现
//todo: ...
}
}
4. 使用
使用时直接获取对应策略,调用相应门面方法传递标识,完成行为算法的动态改变。
@RestController
@RequestMapping(value = "/payment")
public class PaymentController {
@Autowried
private PaymentStrategy paymentStrategy;
@GetMapping
public Result pay() {
return paymentStrategy.pay(PayModeEnum.Wx.toString());
}
}
总结
到此,一个简单、易于维护的策略模式就完成了。对于新加的支付基类只需要实现接口,指定标识和完成算法实现就ok了,对拓展开放,对之前已经完整的算法没有进行修改、关闭了修改,符合设计原则。。