策略模式

GitHub代碼

場景闡述:通過設計一個超類鴨子而讓子類繼承,提取出部分公共方法進行實現,但後續添加需求時,因爲設計上的問題導致無窮無盡的噩夢……

事出有因:超類鴨子負責實現公共的呱呱叫(quack)方法,後續提出需求,想要爲鴨子加入fly方法以提高產品競爭力,但是由於技術失誤,將此fly方法作爲公共方法在超類鴨子中實現後,程序出現bug,橡皮鴨子也會飛啦!
改進策略:通過在橡皮鴨子中覆蓋fly方法,實現自己的獨立方法,但是這會導致每次新增一個鴨子子類時,都要考慮是否需要覆蓋fly方法,並且手動再編碼。

再改進:定義接口呢?提取出fly和quack,分別做成兩個接口,然後由每個鴨子子類去實現;缺點顯而易見,每個鴨子子類都要重寫方法,異常繁瑣,無窮無盡的噩夢。

在這裏插入圖片描述

設計原則:找出應用中可能需要變化之處,把他們獨立出來,不要和那些不需要變化的代碼混在一起。

設計原則:針對接口編程,而不是針對實現編程

“針對接口編程” 的真正意思是“針對超類型編程”。
“針對超類型編程”這句話,可以更明確地說成“變量地聲明類型應該是超類型,通常是一個抽象類或者是一個接口,如此,只要是具體實現此超類型的類所產生的對象,都可以指定給這個變量。這也意味着,聲明類時不用理會以後執行時的真正對象類型”。

通過上述原則,我們嘗試一種新的方式來進行設計。同樣是兩個接口,但是由其對應類來實現具體的行爲,將其和鴨子類分開。這就是可變化的部分。

在這裏插入圖片描述
我們看一下相應的代碼,來更好的理解這種模式。
首先建立一個鴨子抽象類

public abstract class Duck {
    FlyBehavior flyBehavior;
    QuackBehavior quackBehavior;

    public Duck(){}

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

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

    public abstract void display();

    public void performFly(){
        flyBehavior.fly();
    }

    public void performQuack(){
        quackBehavior.quack();
    }

    public void swim(){
        System.out.println("All ducks float, even decoys");
    }
}

然後爲分離出來的行爲新建兩個接口,及其實現類

public interface FlyBehavior {
    public void fly();
}
public class FlyNoWay implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("I can't fly");
    }
}
public class FlyWithWings implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("I'm flying!!");
    }
}
public interface QuackBehavior {
    public void quack();
}
public class Quack implements QuackBehavior{
    @Override
    public void quack() {
        System.out.println("Quack");
    }
}

然後根據需求新建一個鴨子子類

public class ModelDuck extends Duck{
    public ModelDuck(){
        flyBehavior = new FlyNoWay();
        quackBehavior = new Quack();
    }

    @Override
    public void display() {
        System.out.println("I'm a model duck");
    }
}

最後我們用一個測試類來測試一下

public class MiniDuckSimulator {
    public static void main(String[] args) {
        Duck model = new ModelDuck();
        model.performQuack();
        model.performFly();
        model.setFlyBehavior(new FlyWithWings());
        model.performFly();
    }
}

結果如下
在這裏插入圖片描述
當你將兩個類結合起來使用時,就是組合。

設計原則:多用組合,少用繼承。

使用組合建立系統具有很大的彈性,不僅可將算法族封裝成類,更可以“在運行時動態地改變行爲”,只要組合地行爲對象符合正確的接口標準即可。

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

總結:該模式的核心思想是,分離出可變化的部分功能,然後通過一個算法族(也即一個接口及其的一系列實現類)來實現該功能,再將接口與原來的超類進行組合,每當需求發生變動的時候,新建子類中的接口實現類就可以根據需求進行相應的變動。從而實現了可伸縮的,彈性設計。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章