1. 程式人生 > >不一樣的策略模式(設計模式五)

不一樣的策略模式(設計模式五)

前言

什麼是設計模式?說白了就是套路,是經過歷代程式設計師總結出來的。很多時候我們雖然學會了很多套路,但是啥時候使用,使用哪個合適,我想這才是問題的關鍵。
知道怎麼用不知道什麼時候用,這時候看下程式碼風格也行用的上,策略模式是非常容易通過程式碼風格使用上的。
策略模式,為什麼叫策略模式呢?其實策略模式還有一個別名叫做政策(policy)模式,在古代,對不同的國家呢,實行不同的政策,對A呢,採取稅務10%,對B國採取稅務20%。
這樣根據不同國家政策不同呢,在計算機中就是根據不同物件採取不同的方法,就叫做策略模式咯。但是呢,如果直接採用if else 這種行為呢,人們發現過於臃腫,且複用性極差,那麼就形成了這樣一種模式去緩解這個問題。

策略模式屬於物件行為模式,其實不去看概念也很好記,在執行時針對不同物件,去做出相應的行為。至於為什麼不分到結構型或者其他型,只是它更符合行為型,一個類的行為或其演算法可以在執行時更改,這些分類其實沒有絕對的界限,只是有權威人士對其進行了規劃。
那麼策略模式的風格是什麼,檢視正文。

開車出發

public enum PolicyBase
{
    US_Policy,
    DE_Policy,
    FR_Policy
}
public class Strategy
{
    PolicyBase policyBase;

    public Strategy(PolicyBase policyBase) {
        this.policyBase = policyBase;
    }
    public double CalculatePolicy() {
        if (policyBase == PolicyBase.US_Policy)
        {
            return 0.9;
        }
        else if (policyBase == PolicyBase.DE_Policy)
        {
            return 0.8;
        }
        else if (policyBase == PolicyBase.FR_Policy)
        {
            return 0.1;
        }
        return 0;
    }
}

根據不同的國家,採取了不同的政策。這樣一看好像沒有啥問題啊,根據了不同國家制定了不同稅法。
但是呢,在開發程式碼的時間軸上,也就是未來的角度上存在的極大的問題。比如和英國(GB)合作了,我得改吧?然後又和另外一個國家合作了,恐怕又得來一遍。
這時候有人就納悶了,還想不改程式碼?程式碼的確是要改的,但是不能違法了封閉開發原則。


在紅色部分呢,是我們需要繼續往下新增程式碼的地方,也就是我們加一個國家就需要把我們寫過的任何一個區域改一遍。
我想這就很糟糕了,牽扯太大,對於釋出來說就需要測試整個子模組,我想這代價無法讓人接受,這時候策略者模式就出現了。

public enum PolicyBase
{
    US_Policy,
    DE_Policy,
    FR_Policy
}
public interface Policy
{
    double Calculate();
}

public class USPolicy : Policy
{
    public double Calculate()
    {
        throw new NotImplementedException();
    }
}

public class DEPolicy : Policy
{
    public double Calculate()
    {
        throw new NotImplementedException();
    }
}

public class FRPolicy : Policy
{
    public double Calculate()
    {
        throw new NotImplementedException();
    }
}

public class StrategyFactory{
    Policy policy;
    public StrategyFactory(PolicyBase policyBase) {
        switch (policyBase)
        {
            case PolicyBase.US_Policy:
                policy = new USPolicy();
                break;
            case PolicyBase.DE_Policy:
                policy = new DEPolicy();
                break;
            case PolicyBase.FR_Policy:
                policy = new FRPolicy();
                break;
        }
    }
    public Policy GetPolicy() {
        return policy;
    }
}

class SalesOrder
{
    private Policy Policy;

    public SalesOrder(StrategyFactory strategyFactory)
    {
        this.Policy = strategyFactory.GetPolicy();
    }

    public double CalculatePolicy()
    {
        double val = Policy.Calculate();
        return val;
    }

};

上述程式碼中,通過策略者模式把原來的獲取各國的稅法比例變成了SalesOrder類,而這個類不再改變,也就是說所以依賴於獲取各國稅法引數的將依賴於一個穩定的類。
這時候很多納悶了,如果我需要新增一個英國(GB),依然需要在紅色部分就行修改啊,修改的地方如下:


修改的地方一樣多,且還要多加一個GBPolicy類,這不是白忙活了嗎?
首先我們來看下前後依賴關係圖:
使用策略模式前:

使用策略模式後:

這樣一看,不僅是沒有啥好處,還複雜了。
然而這樣一想,我們處理的是解決這個稅法問題這個業務上,可以肯定的就是使用策略模式後,我下面紅框部分穩定了,也就是在二進位制上可以複用,但是上面紅色部分倒是有問題了,耦合太大。
但是呢,我們知道上面複雜部分其實就是簡單工廠模式,問題就回到了如何優化簡單工廠模式了,如果能解決上面紅框的問題,那麼是可行的。
由於篇幅有限,下一篇總結工廠模式到抽象工廠到反射這個演化。
這時候我們看到了,如果遇到了if else 且以後會增加else if,可以用策略模式,去緩解這個問題,增加程式碼複用性。
但是穩定的if else 呢是不需要的,比如說星期一到星期日,這種就是穩定的了,本來處於穩定的,那麼其改變的價值就不是很大。

uml圖

後續補上

總結

策略模式的作用,解決使用不穩定 的if...else 所帶來的複雜和難以維護