策略模式定义:
定义一些算法类,分别将他们封装起来,让他们可以互相替换。策略模式可以让算法的变化独立与使用他们的的客户端(调用者)。
应用场景:
我们有个支付系统,可以支持微信,支付宝,银联,农行等不同支付渠道,由于不同支付渠道处理方式不同,我们会将不同支付渠道分别封装成业务对象,然后根据支付类型选择不同支付对象处理,如下:
/**
* 根据支付类型选择不同支付方式
* @param payType
* @return
*/
public boolean pay(PayType payType){
if (PayType.ALI_PAY.equals(payType)){
return aliPayService.pay();
}else if (PayType.WECHAT_PAY.equals(payType)){
return wechatPayService.pay();
}else if (PayType.ABC_PAY.equals(payType)){
return abcPayService.pay();
}
return false;
}
enum PayType{
ALI_PAY("01","支付宝支付"),
WECHAT_PAY("02","微信支付"),
ABC_PAY("03","农行支付"),
;
private String type;
private String name;
PayType(String type, String name) {
this.type = type;
this.name = name;
}
}
这样实现有什么问题:我们写了大量if else 代码,如果后续要增加建行支付,工行支付,我们还要再原来代码的基础上再增加else if,这样违背了开-闭原则。
如何解决这个问题:使用策略模式,将算法实现从业务中独立出来,形成一系列算法,让这些算法可以互相替换。
如何实现策略模式:
定义策略接口,提供支付方法,然后分别定义实现了策略接口的支付策略类:
interface PayStrategy{
boolean pay();
}
class AliPayStrategy implements PayStrategy{
@Override
public boolean pay() {
System.out.println("ali pay");
return true;
}
}
class WechatPayStrategy implements PayStrategy{
@Override
public boolean pay() {
System.out.println("wechat pay");
return true;
}
}
class ABCPayStrategy implements PayStrategy{
@Override
public boolean pay() {
System.out.println("abc pay");
return true;
}
}
定义策略工厂,根据不同类型,获取不同策略对象。
class PayStrategyFactory{
public static PayStrategy getPayStrategy(PayType payType){
if (PayType.ALI_PAY.equals(payType)){
return new AliPayStrategy();
}else if (PayType.WECHAT_PAY.equals(payType)){
return new WechatPayStrategy();
}else if (PayType.ABC_PAY.equals(payType)){
return new ABCPayStrategy();
}
throw new IllegalArgumentException("this pay type isn`t exists");
}
}
封装完策略对象,接下来就是对原支付代码进行改造:
/**
* 根据支付类型选择不同支付方式
* @param payType
* @return
*/
public boolean pay(PayType payType){
payStrategyFactory.getPayStrategy(payType).pay();
}
总结
通过策略模式,可以很好的替换业务中的if else代码,如何未来新增更多的支付类型,我们也不需要更改业务代码,这让我们的代码更容易扩展和维护。
可能有人会说,虽然业务代码中没有用if else,可策略工厂中使用了if else,而且新增支付类型会改动策略工厂类,这也违背了开-闭原则。其实从策略模式定义可以看出,它的本质是分离算法,选择实现,对调用方来说,它确实是遵循了开-闭原则,无需改动调用方业务代码,就可以增加新的功能。