1. 程式人生 > >設計之禪——靈活的策略模式

設計之禪——靈活的策略模式

一、引言

在平時生活中當我們想要做一件事的時候往往會有許多的途徑和方法,像我們去公司上班,可以走路去,也可以騎車或者開車去;還有像吃飯,我們可以選擇自己做飯吃,也可以出去吃,臉長得好看的還能讓人請吃飯等等,但無論選擇哪種方式,我們最終達到的目的結果都是一樣的,只是過程不一樣。在面向物件的程式設計中,我們就可以把這種變化的行為隔離封裝,實現程式碼的高度擴充套件和複用,也就是我今天要講的策略模式。

二、什麼是策略模式

在探討策略模式之前,我們需要了解幾個OO原則:

  • 封裝變化
  • 多用組合,少用繼承
  • 針對介面程式設計,不針對實現程式設計

封裝變化不用多說,如果不從固有的程式碼中將變化的程式碼抽離出來,那將會讓程式變得非常臃腫; 那為什麼要多用組合,少用繼承

呢?繼承不是OO的基礎嗎?我們來看一個例子:假如有一隻綠頭鴨和紅頭鴨,他們都會跑,也都會叫,因此可以抽象出一個Duck類,有run和quack方法,看似沒有什麼問題,但是當某一天出現了一隻木頭鴨,它也需要繼承Duck類,但是它不會叫也不會跑啊,咋辦呢?當然,我們可以利用方法重寫,在子類中將父類的行為覆蓋掉;這是一個方法,不過我們可能還會出現會飛的野鴨、火箭玩具鴨等等,怎麼辦呢?難道去修改父類,在父類中增加一個fly方法麼?那之前不會飛的鴨子也都可以滿天飛了,至此,我們看到了濫用繼承所帶來的困擾,也發現了鴨子的行為對於鴨子來說是多變的,因此我們可以將鴨子的行為抽象出來為Behavior介面(也就是針對介面程式設計),並利用組合將行為織入到鴨子中,就可以解決上述的問題了。這就是策略模式的核心,來看看《Head First》對其的定義:

策略模式定義了演算法族,分別封裝起來,讓他們之間可以互相替換,此模式讓演算法的變化獨立於使用演算法的客戶。

三、程式碼實現

瞭解了策略模式的定義,我們再來看看如何利用程式碼實現該模式。想象一個冒險遊戲,將其分為角色和武器行為兩大類,角色可以更換任意一種武器來攻擊敵人。

public abstract class Character {

    WeaponBehavior weaponBehavior;

    public void setWeaponBehavior(WeaponBehavior weaponBehavior) {
        this.weaponBehavior =
weaponBehavior; } public void fight() { weaponBehavior.userWeap(); } } public class King extends Character { public King(WeaponBehavior weaponBehavior) { this.weaponBehavior = weaponBehavior; } }
public interface WeaponBehavior {

    void userWeap();

}

public class SwordBehavior implements WeaponBehavior {

    @Override
    public void userWeap() {
        System.out.println("用寶劍揮舞!");
    }

}

public class KnifeBehavior implements WeaponBehavior {

    @Override
    public void userWeap() {
        System.out.println("用匕首刺殺");
    }

}
public static void main(String[] args) {
        Character c = new King(new AxeBehavior());
        c.fight();
        c.setWeaponBehavior(new SwordBehavior());
        c.fight();
    }

在父類角色中,利用組合將武器行為賦予給角色,在角色攻擊時實際是將攻擊行為委託給WeaponBehavior的,同時需要注意,這裡使用的是WeaponBehavior介面,而不是具體的某種武器,這樣我們在程式執行時需要使用哪種武器就只需要呼叫setter方法重新設定他需要的武器即可,這也就是針對介面程式設計,不針對實現程式設計

四、總結

策略模式非常的簡單,也非常的有用,可以將變化的演算法從程式中解耦出來,在程式設計之初時,我們就可以仔細思考發現這部分變化,以便將來的擴充套件。但策略模式也不是完美的,客戶端需要知道所有的策略類以及區別,並自行選擇使用哪一種,同時也會造成大量的策略類和物件,導致系統結構越來越龐大,物件數量過多也會佔用大量的記憶體,可以使用享元模式來減少物件的數量。