《Head First 設計模式》之策略模式


作者:Grey

原文地址:http://www.cnblogs.com/greyzeng/p/5915202.html

模式名稱

策略模式(Strategy Pattern)

需求

模擬鴨子游戲,游戲中會出現各種鴨子,一邊游泳戲水,一邊呱呱叫。我們應該如何設計這個鴨子類呢?

解決方案

首先,我們可以考慮設計一個鴨子的超類Duck,抽象出鴨子的公共方法,然后其他鴨子類型繼承這個超類,對公共方法有自己獨有的實現。

public abstract class Duck {
    
    public abstract void display();
    public abstract void quack(); 
    
    public void swim() {
        System.out.println("all ducks can swim");
    }
    
}
public class RedHeadDuck extends Duck {

    @Override
    public void display() {
        System.out.println("This is RedHeadDuck");
    }

    @Override
    public void quack() {
        System.out.println("RedHeadDuck Quack");
    }
}
public class ModelDuck extends Duck {
    @Override
    public void display() {
        System.out.println("This is ModelDuck");
    }

    @Override
    public void quack() {
        System.out.println("ModelDuck Can not Quack");
    }
}

但是,這種設計,會出現一個問題:
如果要增加一個可以飛的鴨子,我們在超類中增加一個fly()方法,所有繼承這個超類的子類都會有這個方法,導致代碼在多個子類中重復。

public abstract class Duck {
    
    public abstract void display();
    public abstract void quack(); 
    public abstract void fly(); 
    
    public void swim() {
        System.out.println("all ducks can swim");
    }
    
}
public class RedHeadDuck extends Duck{

    @Override
    public void display() {
        System.out.println("This is RedHeadDuck");
    }

    @Override
    public void quack() {
        System.out.println("Gua Gua Gua~~");
    }

    @Override
    public void fly() {
        System.out.println("fly fly fly~~");
    }
}
public class ModelDuck extends Duck{
    @Override
    public void display() {
        System.out.println("This is ModelDuck");
    }

    @Override
    public void quack() {
        System.out.println("Silence");
    }

    @Override
    public void fly() {
        // do nothing
    }
}

更好的一種方法:

分開變化與不變化的部分,因為Duck類里面fly()quack()會隨着鴨子的不同而改變,所以我們需要把這兩個行為從Duck里面分離出來,建立一組新類來代表每個行為

QuackBehavior接口:

interface QuackBehavior {
    void quack();
}

QuackBehavior 具體行為:

public class MuteQuack implements QuackBehavior {
    public void quack() {
        System.out.println("Silence");
    }
}
public class Gua implements QuackBehavior {

    public void quack() {
        System.out.println("Gua Gua Gua~~");
    }
}

FlyBehavior接口:

interface FlyBehavior {
    void fly();
}

FlyBehavior具體行為:

public class FlyWithWings implements FlyBehavior {
    public void fly() {
        System.out.println("fly fly fly~~~");
    }
}
public class FlyNoWay implements FlyBehavior {
    public void fly() {
        // do nothing
    }
}

現在鴨子會將飛行和呱呱叫的動作“委托”給FlyBehaviorQuackBehavior處理,我們在Duck中增加兩個方performFly(),performQuack()

public abstract class Duck {
    Duck() {}

    public FlyBehavior flyBehavior;
    public QuackBehavior quackBehavior;

    public abstract void display();

    public void swim() {
        System.out.println("all ducks can swim");
    }
    public void performFly() {
        flyBehavior.fly();
    }
    public void performQuack() {
        quackBehavior.quack();
    }
}

在每種鴨子繼承超類Duck的時候,只需要在構造函數中設置對應的FlyBehaviorQuackBehavior實例變量即可。

public class RedHeadDuck extends Duck {
    RedHeadDuck() {
        this.quackBehavior = new Gua();
        this.flyBehavior = new FlyWithWings();
    }

    @Override
    public void display() {
        System.out.println("This is RedHeadDuck");
    }
    public void performFly() {
        flyBehavior.fly();
    }
    public void performQuack() {
        quackBehavior.quack();
    }

}
public class ModelDuck extends Duck {
    ModelDuck() {
        this.flyBehavior = new FlyNoWay();
        this.quackBehavior = new MuteQuack();
    }
    @Override
    public void display() {
        System.out.println("This is ModelDuck");
    }
    public void performFly() {
        flyBehavior.fly();
    }
    public void performQuack() {
        quackBehavior.quack();
    }

}

同時,我們可以在Duck類中增加對FlyBehaviorQuackBehaviorsetter/getter方法,這樣我們就可以動態改變鴨子的行為了

public abstract class Duck {
    Duck() {}

    public FlyBehavior flyBehavior;
    public QuackBehavior quackBehavior;

    public abstract void display();

    public void swim() {
        System.out.println("all ducks can swim");
    }
    public void performFly() {
        flyBehavior.fly();
    }
    public void performQuack() {
        quackBehavior.quack();
    }

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

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

測試代碼:

public class DuckTest {
    public static void main(String[] args) {
        Duck redHeadDuck = new RedHeadDuck();
        redHeadDuck.display();
        redHeadDuck.performFly();
        redHeadDuck.performQuack();

        System.out.println();

        Duck modelDuck = new ModelDuck();
        modelDuck.display();
        modelDuck.performFly();
        modelDuck.performQuack();

        System.out.println();

        System.out.println("I want that modelduck can fly");
        modelDuck.setFlyBehavior(new FlyWithWings());
        modelDuck.performFly();
    }
}

輸出結果:

This is RedHeadDuck
fly fly fly~~~
Gua Gua Gua~~

This is ModelDuck
can not fly
Silence

I want that modelduck can fly
fly fly fly~~~

完整代碼: Strategy Pattern Source


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM