说明
当我们网上购物支付结算的时候,手机 app 会提示我们使用那种方式进行支付,我们选择不同的方式就会从不同的地方扣钱,这就是策略模式的应用,根据不同的选择使用不同的策略来处理同一种问题
当然,策略模式的编码方法有很多,最常用的就是 if-else 、switch 条件分支判断,如果策略过多,就会出现很多 if-else,代码很不美观,因此,使用工厂模式对策略模式进行优化,可以很好的解决这些问题
策略模式一般步骤
- 提取所有策略的公共接口
- 不同策略都实现统一公共接口
- 选择不同的策略来解决问题
策略模式场景演绎
下面通过网上购物的案例来一步步了解策略模式及其优化方法
首先,所有的支付方式都实现类 Pay 接口,该接口下只有一个方法, pay
/**
* 支付接口
*/
public interface Pay {
void pay(int money);
}
有了这个接口,各大厂商就会实现这个接口来做出属于自己的支付软件,有 AliPay,JDPay,ApplePay 等等
public class AliPay implements Pay{
@Override
public void pay(int money) {
System.out.println("使用alipay支付了" + money + "元");
}
}
public class JDPay implements Pay{
@Override
public void pay(int money) {
System.out.println("使用JDPay支付了" + money + "元");
}
}
public class ApplePay implements Pay{
@Override
public void pay(int money) {
System.out.println("使用ApplyPay支付了" + money + "元");
}
}
有了这些支付软件,购物平台就会引进这些支付软件提供的接口,来实现多软件支付
/**
* 网上购物app
*/
public class ShoppingApp {
/**
* 选择支付方式
*/
public Pay selectPay(String payName){
if ("aliPay".equals(payName)){
return new AliPay();
}else if ("JDPay".equals(payName)){
return new JDPay();
}else if ("applePay".equals(payName)){
return new ApplePay();
}else {
return new AliPay();
}
}
}
最后我们写一个主函数来模拟一下线上购物的场景
public class Main {
public static void main(String[] args) {
ShoppingApp app = new ShoppingApp();
Pay pay = app.selectPay("aliPay");
pay.pay(100);
}
}
查看控制台的输出
使用工厂模式优化
上面选择策略的过程是用 if-else 的方式来实现的,当只有很少的策略的时候,可以用这种方式,一旦策略很多,就会有很多 if-else,代码很不雅观,而且每一种策略都是 new 出来的,策略复用性不高。如果使用加入工厂模式,就会很好的解决问题
现在我们来对 ShoppingApp 进行重构,如下所示
/**
* 网上购物app
*/
public class ShoppingApp {
private static Map<String, Pay> payMap = new HashMap<>();
static{
payMap.put("aliPay", new AliPay());
payMap.put("JDPay", new JDPay());
payMap.put("applePay", new ApplePay());
}
/**
* 选择支付方式
*/
public Pay selectPay(String payName){
Pay pay = payMap.get(payName);
return Optional.ofNullable(pay).orElse(new AliPay());
}
}
再来进行测试,查看控制台结果,同样的结果
最后
使用这种硬编码的方式将厂商实现的支持策略添加到 Map 中,确实解决了冗余的 if-else 问题,但是,代码的可扩展性不高,因为只能使用在 map 中有的策略,添加新的策略需要修改代码,不符合开闭原则。因此还可以继续优化,新建一个方法往 map 中放入新的策略,或者在配置文件中定义策略类的全限定名,使用反射来创建策略类并添加到 map 中,这样就能很好的解决