策略模式定義:
定義一些算法類,分別將他們封裝起來,讓他們可以互相替換。策略模式可以讓算法的變化獨立與使用他們的的客戶端(調用者)。
應用場景:
我們有個支付系統,可以支持微信,支付寶,銀聯,農行等不同支付渠道,由於不同支付渠道處理方式不同,我們會將不同支付渠道分別封裝成業務對象,然後根據支付類型選擇不同支付對象處理,如下:
/**
* 根據支付類型選擇不同支付方式
* @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,而且新增支付類型會改動策略工廠類,這也違背了開-閉原則。其實從策略模式定義可以看出,它的本質是分離算法,選擇實現,對調用方來說,它確實是遵循了開-閉原則,無需改動調用方業務代碼,就可以增加新的功能。