設計模式之策略模式

1.定義
策略模式定義了算法族,分別封裝起來,讓它們之間可以互相替換,此模式讓算法的變化獨立於使用算法的客戶。
這些算法族可以看成對象的一系列行爲。
2.場景描述
現在要開發一款鴨子游戲,目前是所有的鴨子都會游泳,但是綠頭鴨(MallardDuck)不會呱呱叫,只會吱吱叫;橡皮鴨不會飛等。後續還有可能會出現唐老鴨角色,即不會飛,也不會吱吱叫,呱呱叫,但是會說話等突然情況需要添加或修改遊戲角色。
3.設計類關係圖
在這裏插入圖片描述
4.代碼實現

1)Duck抽象類

public abstract class Duck {
    /**
     * 爲行爲接口類型聲明兩個引用變量,所有duck子類都繼承
     * 聲明爲接口類型,這樣每個duck對象都能動態的設置這些變量,在運行時引用正確的行爲類型
     */
    FlyBehavior flyBehavior;
    QuackBehavior quackBehavior;
    public Duck(){
    }
    public abstract void display();

    public void performFly(){
        //委託給行爲類
        flyBehavior.fly();
    }

    public FlyBehavior getFlyBehavior() {
        return flyBehavior;
    }

    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }

    public QuackBehavior getQuackBehavior() {
        return quackBehavior;
    }

    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }

    public void performQuack(){
        //委託給行爲類
        quackBehavior.quack();
    }

    public void swim(){
        System.out.println("所有的鴨子都會游泳");
    }
}

2)MallardDuck類

public class MallardDuck extends Duck {
    /**
     * 因爲MallardDuck 繼承Duck,所以具有quackBehavior和flyBehavior實例變量
     * MallardDuck 使用Quack類處理呱呱叫,當performQuack()被調用時,叫的職責被委託給Quack對象
     * Fly行爲也一樣
     */
    public MallardDuck(){
        quackBehavior = new Quack();
        flyBehavior = new FlyWithWings();
    }
    public void display() {
        System.out.println("I`m a real Mallard duck");
    }
}

3)FlyBehavior接口

/**
 * 這是一個接口,所有飛行類都要實現它,所有新的飛行類都必須實現fly方法
 * Quack接口也一樣
 */
public interface FlyBehavior {
    void fly();
}

4)FlyWithSwing類

public class FlyWithWings implements FlyBehavior {
    /**
     * 這是飛行行爲的實現,給會飛的duck使用
     */
    public void fly() {
        System.out.println("我飛起來了");
    }
}

5)FlyNoWay類

public class FlyNoWay implements FlyBehavior {
    public void fly() {
        System.out.println("不會飛");
    }
}

6)QuackBehavior接口

public interface QuackBehavior {
     void quack();
}

7)Quack類

public class Quack implements QuackBehavior{
    public void quack() {
        System.out.println("呱呱叫");
    }
}

8)MuteQuack類

public class MuteQuack implements QuackBehavior{
    public void quack() {
        System.out.println("不會叫");
    }
}

9)測試類

public class DuckTest {
    public static void main(String[] args) {
        Duck mallard = new MallardDuck();
        //這時會調用MallardDuck繼承來的performFly()方法,委託給該對象
        //的QuackBehavior對象處理,即FlyWithWings類調用fly()方法
        mallard.performFly();
        mallard.performQuack();
    }
}

5.策略模式遵循的oo設計原則

1)找出應用中可能需要變換之處,把它們獨立出來
2)針對接口編程,不針對實現編程
3)多用組合,少用繼承

在上述的代碼中,你會發現MallardDuck的構造器中是針對具體實現編程,但是我們在Duck類提供了FlyBehavior和QuackBehavior的set()方法,可以實現在運行時動態改變行爲類。此時的測試類修改爲:

public class DuckTest {
    public static void main(String[] args) {
        Duck mallard = new MallardDuck();
        //這時會調用MallardDuck繼承來的performFly()方法,委託給該對象
        //的QuackBehavior對象處理,即FlyWithWings類調用fly()方法
        mallard.performFly();
        mallard.performQuack();
        mallard.setFlyBehavior(new FlyNoWay());
        mallard.setQuackBehavior(new MuteQuack());
        System.out.println("動態改變行爲類了,你看!");
        mallard.performFly();
        mallard.performQuack();
    }
}

運行結果
在這裏插入圖片描述
如果遊戲需要添加一種利用動力的飛行行爲,這時只需要將實現飛行行爲的具體實現實現FlyBehavior接口即可,這樣某個Duck子類具有該飛行行爲時可以使用該類。
6.策略模式的缺點
此刻你會發現,如果要添加某一種行爲,就需要不斷的添加子類,所以使用策略模式可能會產生大量的類。

最後,再來回顧一下策略模式:封裝可以互換的行爲,並使用委託來決定要使用哪一個

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章