策略模式(Strategy Pattern)(二):HeadFirst中鴨子的實現
一、問題描述
joe上班的公司做了一套成功的模擬鴨子的遊戲:SimUDuck,遊戲中會出現各種鴨子,一邊游泳,一邊呱呱叫,由於公司競爭壓力加劇,必須重新設計鴨子(Duck)類,要求是:便於產生新的鴨子物件,可為鴨子新增新的行為,易於維護,動態設定行為。
二、類圖
說明:
1.對各種鴨子的解釋:
RedHeadDuck:紅頭鴨,可以用翅膀飛,呱呱叫。
RubberDuck:橡皮鴨,不會飛,吱吱叫。
ModelDuck:模型鴨,不會飛,呱呱叫。
DecoyDuck:誘餌鴨,不會飛,不會叫。
MallardDuck:野鴨,會用翅膀飛,呱呱叫。
2
使用FlyBehavior和QuackBehavior介面型別便於以後增加新的飛行行為或呱呱叫行為,不會影響到既有的行為類,也不會影響使用行為的鴨子類。同樣,這也可以讓飛行行為和呱呱叫行為被其他物件複用,因為這些行為已經與鴨子類無關了,你也可以將其用在雞和大鵝身上。
3.對飛行行為的解釋:
FlyWithWings用翅膀飛。
FlyNoWay:不會飛。
FlyRocketPowered:使用火箭動力飛行(鴨子的飛行行為可以動態改變)。
4.對呱呱叫(此呱呱叫泛指鴨子的叫聲而不是紅頭鴨的“呱呱叫”)行為的解釋:
Quack:呱呱叫。
FakeQuack:假叫。
Squeak:吱吱叫。
MuteQuack:不會叫。
5.所有的鴨子都會浮水,所以將swim()方法定義且實現為抽象父類Duck中的具體類。
所有的鴨子的外觀隨鴨子種類不同而不同,所以將display()方法定義為Duck中的抽象方法,讓各個鴨子子類實現。
6.Duck中的performFly()和performQuack()方法:
鴨子物件不親自處理飛行行為和呱呱叫行為,而是委託給飛行行為類FlyBehavior和呱呱叫行為類QuackBehavior。例如performFly()方法實現為
public void performFly() {
flyBehavior.fly();
}
7.Duck的setFlyBehavior()和setQuackBehavior()用於動態設定鴨子的行為。
8.類不僅可以表示具體的“東西”,還.可以用一個類來表示行為,FlyBehavior表示飛行行為,QuackBehavior表示呱呱叫行為。
三、程式碼實現
1.鴨子超類Duck:
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck() {
}
//動態設定飛行行為
public void setFlyBehavior (FlyBehavior fb) {
flyBehavior = fb;
}
public void setQuackBehavior(QuackBehavior qb) {
quackBehavior = qb;
}
//不同的鴨子長相不同
abstract void display();
//將飛行行為委託給飛行行為類處理
public void performFly() {
flyBehavior.fly();
}
//將呱呱叫行為委託給呱呱叫行為類處理
public void performQuack() {
quackBehavior.quack();
}
//所有鴨子都會浮水
public void swim() {
System.out.println("All ducks float, even decoys!");
}
}
2.行為:
(1)飛行行為FlyBehavior:
public interface FlyBehavior {
public void fly();
}
(2)呱呱叫行為QuackBehavior:
public interface QuackBehavior {
public void quack();
}
3.具體的行為:
(1)飛行行為:
用翅膀飛:
public class FlyWithWings implements FlyBehavior {
public void fly() {
System.out.println("I'm flying!!");
}
}
不會飛:
public class FlyNoWay implements FlyBehavior {
public void fly() {
System.out.println("I can't fly");
}
}
使用火箭動力飛:
public class FlyRocketPowered implements FlyBehavior {
public void fly() {
System.out.println("I'm flying with a rocket");
}
}
(2)呱呱叫行為:
呱呱叫:
public class Quack implements QuackBehavior {
public void quack() {
System.out.println("Quack");
}
}
吱吱叫:
public class Squeak implements QuackBehavior {
public void quack() {
System.out.println("Squeak");
}
}
假叫:
public class FakeQuack implements QuackBehavior {
public void quack() {
System.out.println("Qwak");
}
}
不會叫:
public class MuteQuack implements QuackBehavior {
public void quack() {
System.out.println("<< Silence >>");
}
}
4.各種鴨子
紅頭鴨:
public class RedHeadDuck extends Duck {
public RedHeadDuck() {
flyBehavior = new FlyWithWings();
quackBehavior = new Quack();
}
public void display() {
System.out.println("I'm a real Red Headed duck");
}
}
模型鴨:
public class ModelDuck extends Duck {
public ModelDuck() {
flyBehavior = new FlyNoWay();
quackBehavior = new Quack();
}
public void display() {
System.out.println("I'm a model duck");
}
}
野鴨:
public class MallardDuck extends Duck {
public MallardDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
public void display() {
System.out.println("I'm a real Mallard duck");
}
}
橡皮鴨:
public class RubberDuck extends Duck {
public RubberDuck() {
flyBehavior = new FlyNoWay();
quackBehavior = new Squeak();
}
public void display() {
System.out.println("I'm a rubber duckie");
}
}
誘餌鴨:
public class DecoyDuck extends Duck {
public DecoyDuck() {
setFlyBehavior(new FlyNoWay());
setQuackBehavior(new MuteQuack());
}
public void display() {
System.out.println("I'm a duck Decoy");
}
}
5.測試
public class MiniDuckSimulator {
public static void main(String[] args) {
MallardDuck mallard = new MallardDuck();
RubberDuck rubberDuckie = new RubberDuck();
DecoyDuck decoy = new DecoyDuck();
ModelDuck model = new ModelDuck();
mallard.performQuack();
rubberDuckie.performQuack();
decoy.performQuack();
model.performFly();
model.setFlyBehavior(new FlyRocketPowered());
model.performFly();
}
}
四、體現的設計原則
(1)封裝變化
鴨子的飛行行為和呱呱叫行為都是變化的,將它們封裝到兩個行為類中,在以後可以輕易地改動或擴充行為而不影響其他部分,系統更有彈性。
(2)多用組合,少用繼承
Duck內部持有FlyBehavior和QuackBehavior的引用,鴨子的行為是和行為物件“組合”而來的,使系統具有很大的彈性,並且可以動態設定行為。
(3)針對介面程式設計,不針對實現程式設計
Duck內部的屬性flyBehavior和quackBehavior都是介面型別的,將具體行為與鴨子類分離開來,實現瞭解耦,並且我們能夠在執行時通過多型的魔力動態地指定行為的不同的實現類。
轉載請註明出處:http://blog.csdn.net/jialinqiang/article/details/8871327