1. 程式人生 > >設計模式:HelloWorld之策略模式

設計模式:HelloWorld之策略模式

for plane span 代碼實現 class 一個 取出 影響 設計

一.概述

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

策略模式的三要素:

抽象策略角色: 策略類,通常由一個接口或者抽象類實現。

具體策略角色:包裝了相關的算法和行為。

環境角色:持有一個策略類的引用,最終給客戶端調用。

二.案例驅動

提出問題:要求做出一套模擬鴨子的遊戲,遊戲中會出現各種鴨子,它們一邊遊泳,一邊呱呱叫。

分析:根據OO設計思想,無非就是使各種鴨子實現自己相應的功能即可,如鴨子遊泳,鴨子呱呱叫。

解決方案1.0:設計一個接口(Duck),然後根據需要完成不同的實現,如紅頭鴨,綠頭鴨。。。。

public interface
Duck { public abstract void quack(); public abstract void swim(); public abstract void display(); } public MallardDuck implements Duck{ public abstract void quack(){ System.out.println("呱呱~~"); } public abstract void swim(){ System.out.println("歡快的遊泳~~"); } public
abstract void display(){ System.out.println("綠頭鴨~~"); } } public RedHeadDuck implements Duck{ public abstract void quack(){ System.out.println("呱呱~~"); } public abstract void swim(){ System.out.println("歡快的遊泳~~"); } public abstract void display(){ System.out
.println("紅頭鴨~~"); } }

突然增加一個新的需求,要求有野鴨,除了具有這兩個功能外,還會飛(fly),同時還有一種橡皮鴨,叫聲時吱吱。。

此時該方案便暴露了一下缺點。。。。

缺點:牽一發而動全身,我們很難知道所有鴨子的行為,當針對有些實現需要添加新的功能時

解決方案1.1

為了更加靈活,面向接口編程。

public interface Flyable {
    public abstract void fly();
}
public interface Swimable {
    public abstract void swim();
}
public interface Quackable {
    public abstract void quack();
}
public RedHeadDuck implements Quackable implements Swimable {...}
public WildDuck implements Quackable implements Swimable implements Flyable {...}

如果有一萬種鴨子,這種方式簡直不敢想象,重復代碼太多!

解決方案2.0

采用策咯模式解決此問題。

step1:把會變化的部分取出來,並封裝起來,好讓其他代碼不受影響。

技術分享圖片

step2:封裝行為的大局觀

技術分享圖片

step3:代碼實現

抽象策略角色

// 飛行行為
public interface FlyBehavior {
    public abstract void fly();
}
// 叫聲行為
public interface QuackBehavior {
    public abstract void quack();
}

具體策略對象

// 橡皮鴨叫
public RubberDuckBehavior implements QuackBehavior {
    public abstract void quack(){
        System.out.println("吱吱~~");
    }
}
// 野鴨叫
public WildDuckBehavior implements QuackBehavior {
    public void quack(){
        System.out.println("嘎嘎~~");
    }
}
// 大黃鴨叫
public YellowDuckBehavior implements QuackBehavior {
    public void quack(){
        System.out.println("呱呱~~");
    }
}
// 不會飛
public FlyNoWay implements FlyBehavior {
    public void fly(){
        System.out.println("不會飛~~");
    }
}
// 用翅膀飛
public FlyWithWings implements FlyBehavior {
    public void fly(){
        System.out.println("用翅膀飛~~");
    }
}
// 螺旋槳飛
public FlyLikePlane implements FlyBehavior {
    public void fly(){
        System.out.println("用螺旋槳~~");
    }
}

環境角色

抽象類

public abstract class Duck {
     FlyBehavior flyBehavior;
     QuackBehavior quackBehavior;
    // 動態設定行為
    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }
    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }
    public void performFly() {
        flyBehavior.fly();
    }
    public void performQuack() {
        quackBehavior.quack();
    }
    public abstract display() {}
    public void swim() {
        System.out.println("鴨子天生會遊泳!");
    }
}

實現

public class WildDuck implements Duck {
     FlyBehavior flyBehavior;
     QuackBehavior quackBehavior;
    public WildDuck() {
        // 默認會飛,野鴨叫嘎嘎
        this.flyBehavior = new FlyWithWings();
        this.quackBehavior = new WildDuckBehavior();
    }
    // 動態設定行為
    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }
    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }
    public void performFly() {
        flyBehavior.fly();
    }
    public void performQuack() {
        quackBehavior.quack();
    }
    public void display() {
        System.out.println("這是一只野鴨!");
    }
    public void swim() {
        System.out.println("鴨子天生會遊泳!");
    }
}

需求改變:野鴨的翅膀受傷,不會飛了

    public static void main(String[] args) {
        Duck duck = new WildDuck();
        duck.setFlyBehavior(new FlyNoWay());
        duck.performFly();// 輸出:不會飛~~
    }

需改改變:新增一只火箭鴨,能飛到太空,不會遊泳,外形像火箭一樣,叫嘎嘎

public RocketDuckFlyBehavior implements FlyBehavior {
    public  void fly(){
        System.out.println("飛到太空~~");
    }
}
public class RocketDuck implements Duck {
     FlyBehavior flyBehavior;
     QuackBehavior quackBehavior;
    public WildDuck() {
        // 默認會飛,野鴨叫嘎嘎
        this.flyBehavior = new RocketDuckFlyBehavior();
        this.quackBehavior = new WildDuckQuackBehavior();
    }
    // 動態設定行為
    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }
    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }
    public void performFly() {
        flyBehavior.fly();
    }
    public void performQuack() {
        quackBehavior.quack();
    }
    public abstract display() {
        System.out.println("外形像火箭~~");
    }
    public void swim() {
        System.out.println("不會遊泳");
    }
}

三.策略模式的優缺點

優點:

1.策略模式提供了管理相關的算法族的辦法。策略類的等級結構定義了一個算法或行為族。恰當使用繼承可以把代碼轉移到符類,從而避免重復代碼 。

2.在策略模式中利用組合和委托來讓環境角色擁有執行算法的能力,這也是繼承的一種更輕便的替代方案。

3.提供了對開放—封閉原則的完美支持,將算法封裝在獨立的strategy中,使得它們易於切換,易於理解,易於擴展

4.利用組合、委托和多態等技術和思想,可以有效地避免多重條件選擇語句

缺點:

 1.客戶端必須知道所有的策略類,區分他們之間的區別,並自行決定使用哪一個策略類。

 2.針對每一種行為情況需要創建一個策略類,造成很多的策略類。
個人站點地址:www.mycookies.cn(適合java初學者的個人博客項目) github:https://github.com/liqianggh/blog

設計模式:HelloWorld之策略模式