作者: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
}
}
現在鴨子會將飛行和呱呱叫的動作“委托”給FlyBehavior和QuackBehavior處理,我們在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的時候,只需要在構造函數中設置對應的FlyBehavior和QuackBehavior實例變量即可。
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類中增加對FlyBehavior和QuackBehavior的setter/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
