設計模式:HelloWorld之策略模式

一.概述

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

策略模式的三要素:git

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

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

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

二.案例驅動

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

分析:根據OO設計思想,無非就是使各類鴨子實現本身相應的功能便可,如鴨子游泳,鴨子呱呱叫。this

解決方案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),同時還有一種橡皮鴨,叫聲時吱吱。。code

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

缺點:牽一髮而動全身,咱們很難知道全部鴨子的行爲,當針對有些實現須要添加新的功能時

解決方案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  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 class FlyNoWay implements FlyBehavior {
    public void fly(){
        System.out.println("不會飛~~");
    }
}
// 用翅膀飛
public class FlyWithWings implements FlyBehavior {
    public void fly(){
        System.out.println("用翅膀飛~~");
    }
}
// 螺旋槳飛
public class 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 void display();
    public void swim() {
        System.out.println("鴨子天生會游泳!");
    }
}

實現

public class WildDuck extends 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 extends 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

相關文章
相關標籤/搜索