策略模式
策略模式
策略模式属于 23 中设计模式中
行为模式
的一种, 其目的是封装类似算法的不同实现, 根据策略选择其中一种去执行
关键
特点
- 一个行为具有不同的实现方法
- 不同的实现方法之间的选择是互斥的,只能使用一种
优点
- 干掉语法中的
if...else...
, 方便维护 - 可以任意扩展相同的实现
实践的关键
- 不同的实现方式需要抽象出一个实现接口
业务场景
原始实现
我们有一个支付场景的实现,用户可以选择 支付宝、微信支付、花呗 进行支付
那么,我们的实现可能像下面这个样子
public class AliPay {
public void spendMoney(BigDecimal amount) {
System.out.println("用 支付宝 支付");
}
public void ohNo() {
System.out.println("下个月要吃土了");
}
}
public class WeChatPay {
public void costMoney(BigDecimal amount) {
System.out.println("使用 微信 支付");
}
public void notPay() {
System.out.println("东西太贵了");
}
}
public class JustPay {
public void huaQian(BigDecimal amount) {
System.out.println("使用 花呗 支付");
}
public void buMaiLe() {
System.out.println("冲动型消费是不科学的");
}
}
这里故意胡乱命名 以模仿在项目中各种支付方式的乱糟糟的实现
优化实现
不难看出,这里所有的支付场景 都有2个动作,一个是 支付
、一个是取消支付
那么,我们可以抽象出以下接口并重构已有的实现类
public interface PaymentStrategy {
public void payment(BigDecimal amount);
public void cancel();
}
这样,我们的各种支付实现就看起来舒服多了
public class AliPayStrategy implements PaymentStrategy {
@Override
public void payment(BigDecimal amount) {
System.out.println("用 支付宝 支付");
}
@Override
public void cancel() {
System.out.println("取消 支付宝 支付");
}
}
public class WeChatStrategy implements PaymentStrategy {
@Override
public void payment(BigDecimal amount) {
System.out.println("使用 微信 支付");
}
@Override
public void cancel() {
System.out.println("取消 微信 支付");
}
}
public class JustPayStrategy implements PaymentStrategy {
@Override
public void payment(BigDecimal amount) {
System.out.println("使用 花呗 支付");
}
@Override
public void cancel() {
System.out.println("取消 花呗 支付");
}
}
关键点
那么,如何将这些策略放到一起,并方便查找和抉择呢
首先我们肯定希望通过接口调用,而不是显式的声明策略的具体实现类
// 我们不期望的实现方式
PaymentStrategy paymentStrategy = new AliPay();
paymentStrategy.payment(new BigDecimal("3.14"));
// 我们期望的使用方式
PaymentStrategy paymentStrategy == null;
// ... 神秘代码
paymentStrategy.payment(new BigDecimal("3.14"));
我们期望通过一个集合之类的数据结构,拿到我们想用的具体实现,那么Map 是一个不错的选择
/**
* "aliPay" --> AliPayStrategy
* "wechat" --> WeChatStrategy
* "justPay" --> JustPayStrategy
*/
Map<String, PaymentStrategy> paymentStrategy;
那么,我们是否需一个初始化的方法,或者工厂模式之类的去归置这些实现呢?
答案是否定的
,这会导致代码变的复杂和不容易维护,我们应该考虑使用 依赖注入
实现,如果你是在使用Spring 框架的话, 这一切将变的非常轻松
/**
* "aliPayStrategy" --> AliPayStrategy
* "weChatStrategy" --> WeChatStrategy
* "justPayStrategy" --> JustPayStrategy
*/
@Autowired
Map<String, PaymentStrategy> paymentStrategy;
不难发现, 这里key 就是Spring bean 的名称,自然,我们可以联想到
@Service("aliPay")
public class AliPayStrategy implements PaymentStrategy {
//... 省略
}
@Service("weChat")
public class WeChatStrategy implements PaymentStrategy {
//... 省略
}
@Service("justPay")
public class JustPayStrategy implements PaymentStrategy {
//... 省略
}
这样,可以轻松的定义策略名称并使用依赖注入完成 策略模式
的实现