1、政策模式概念了解
官方定義:針對一組算法或行為,将每一個算法或行為封裝到具有共同接口的獨立的類中,進而使得它們可以互相替換。政策模式使得算法可以在不影響到用戶端的情況下發生變化。
為了友善了解概念我們先來模拟一個需求場景: 現在假設公司要你開發一個支付抵扣功能。背景:現在有支付寶、微信、銀聯等支付管道。需求:用在支付時可以用一種叫代金券的虛拟券抵扣支付金額,不排除今後會新增其他抵扣方式。
接下來我們來看看下面幾種不好的設計:
abstract class 支付基類{
抵扣方法(){}
abstract 支付方法();
}
class 支付寶類 extends 支付基類{
支付方法(){
抵扣金額=抵扣方法()
....
}
}
class 微信類 extends 支付基類{
支付方法(){
抵扣金額=抵扣方法()
....
}
}
class 銀聯類 extends 支付基類{
支付方法(){
抵扣金額=抵扣方法()
....
}
}
....
上面設計中,将抵扣方法寫在基類中,這樣各個子類都可以調用。
過了一段時間,需求有所改變,要求某些支付管道(例如:銀聯管道)不能抵扣,此時我們就要改代碼,在銀聯類裡覆寫抵扣方法。如果類似情況較多那麼每個支付管道都需要檢查是否需要重寫抵扣方法。
再比如,新增了一種支付管道叫積分抵扣(類似于淘寶),某些支付管道隻能用積分抵扣,這樣也需要在支付類裡重寫抵扣方法,但這些抵扣方法不能被重用。
是以這樣的設計至少不是一種優雅的設計。
PS:使用繼承來實作代碼複用不是一種很好的方法。
2、政策模式的核心思想
根據上面的例子我們可以看出抵扣的這個行為,可能有很多種方式,并且下個的抵扣方式是什麼樣,我們無法預估。因為我們無法預估需求。
對于像這樣的場景,一個類有一組算法或者行為 (上面的例子中指的就是“抵扣”,抵扣方式有很多種是以說他有“一組算法或行為”),這樣的需求該怎麼設計呢?
“将每一個算法或行為封裝到具有共同接口的獨立的類中”,意思是把抵扣的每個行為看成一個個類,具體抵扣規則寫在類方法裡,這些類實作同一個接口。具體看下面UML:

在上面的設計中,我們把抵扣的行為不放在支付基類或子類裡,而是将他獨立出來,基類裡包含設定行為的方法,這樣可以動态的改變行為。這樣的設計支付類将不用知道抵扣細節,進而解耦。
5、代碼示例
5.1、代碼示例(Java)
用戶端類 Client.java
package strategy;
public class Client {
public static void main(String[] args)
{
PayBase zfb = new Zhifubao();
zfb.setDikouBehavior(new DaiJinQuan());
zfb.payAction();
zfb.setDikouBehavior(new JIfen());
zfb.payAction();
} }
支付基類 PayBase.java
package strategy;
public abstract class PayBase {
DikouBehavior dikou;
public void setDikouBehavior(DikouBehavior dk){
dikou = dk;
}
protected abstract void payAction();
}
支付寶類 Zhifubao.java
package strategy;
class Zhifubao extends PayBase{
public void payAction(){
dikou.dikouAction();
System.out.println("支付寶支付");
}
}
微信類 Weixin.java
package strategy;
class Weixin extends PayBase{
public void payAction(){
System.out.println("微信支付");
}
}
銀聯類 Yinlian.java
package strategy;
class Yinlian extends PayBase{
public void payAction(){
System.out.println("銀聯支付");
}
}
下面是抵扣接口和具體抵扣行為類:
抵扣接口 DikouBehavior.java
package strategy;
public interface DikouBehavior {
public void dikouAction();
}
代金券抵扣類Daijinquan.java
package strategy;
public class DaiJinQuan implements DikouBehavior {
public void dikouAction(){
System.out.println("代金券抵扣");
}
}
積分抵扣類 JIfen.java
package strategy;
public class JIfen implements DikouBehavior {
public void dikouAction(){
System.out.println("積分抵扣");
}
}
大家可以看到在用戶端類裡,可以自由選擇任意一種抵扣方式,其他類代碼均不用改動。當有新的抵扣方式加入時候,隻要新增抵扣類。而用戶端代碼可以根據參數來選擇抵扣方式。
這樣的設計把經常變化的部分抽離出來封裝,不變化的代碼無需改動!!