設計模式之-降龍十八掌

本文代碼較多且綜合了好幾種設計模式使用,建議收藏或者慢慢觀看。git

本文將綜合抽象工廠、組合模式、裝飾器模式、適配器模式、觀察者模式等模式運用在本例子中。對於不熟悉這些模式的讀者能夠閱讀歷史文章學習增強本身的代碼心法。完整代碼在 github:https://github.com/UniqueDong/zero-design-patterns 對應的 com.zero.headfirst.verb 包目錄下。github

適配器模式

首先咱們從製造一個屏幕模擬器開始,模擬鴨子叫,根據需求咱們先定義 Quackable接口,而後分別定義MallarDuck、RedheadDuck、RubberDuck、DuckCall等不一樣的鴨子實現呱呱叫接口,這個時候有鴨子出現的地方也出現了鵝混在其中,咱們就經過適配器模式適配成鴨子。設計模式

/**
 * 鴨子呱呱叫接口
 */
public interface Quackable {
    /**
     * 呱呱叫
     */
    void quack();
}

/**
 * 鴨子叫玩具
 */
public class DuckCall implements Quackable {
    @Override
    public void quack() {
        System.out.println("鴨子模擬器叫...");
    }
}

public class MallarDuck implements Quackable {
    @Override
    public void quack() {
        System.out.println("標準綠頭鴨呱呱叫...");
    }
}

public class RedheadDuck implements Quackable {
    @Override
    public void quack() {
        System.out.println("紅頭鴨呱呱叫...");
    }
}

public class RubberDuck implements Quackable {
    @Override
    public void quack() {
        System.out.println("橡皮鴨吱吱叫...");
    }
}
複製代碼

如今各類鴨子定義好了,咱們定義鵝 Goose框架

/**
 * 天鵝,僞裝鴨子在模擬器中出現
 */
public class Goose {
    public void honk() {
        System.out.println("天鵝叫聲,額");
    }
}複製代碼

這個時候須要適配器將鵝適配成鴨子,適配器持有鵝的引用,鵝就是被適配對象,同時適配器實現 Quackable接口,當調用 quack()的時候實際是委託調用了honk()方法。ide

/**
 * 將天鵝適配成鴨子
 */
public class GooseAdapter implements Quackable {
    /**
     * 持有被修飾的對象
     */
    private Goose goose;

    public GooseAdapter(Goose goose) {
        this.goose = goose;
    }

    @Override
    public void quack() {
        goose.honk();
    }
}複製代碼

最後咱們的屏幕模擬器登場,展現滿屏呱呱叫的鴨子與鵝。學習

public class DuckSimulation {
    public static void main(String[] args) {
        DuckSimulation simulation = new DuckSimulation();
        simulation.simulate();
    }

    /**
     * 模擬屏幕展現功能
     */
    private void simulate() {
        Quackable redheadDuck = new RedheadDuck();
        Quackable mallarDuck = new MallarDuck();
        Quackable rubberDuck = new RubberDuck();
        Quackable duckCall = new DuckCall();
        GooseAdapter gooseAdapter = new GooseAdapter(new Goose());
        simulate(redheadDuck);
        simulate(mallarDuck);
        simulate(rubberDuck);
        simulate(duckCall);
        simulate(gooseAdapter);
    }

    private void simulate(Quackable quackable) {
        quackable.quack();
    }

}
複製代碼

裝飾器-統計鴨子叫的次數

如今繼續新增需求,在鴨子類不修改的狀況下咱們要統計叫的次數。咱們建立一個裝飾者,經過把鴨子包裝進裝飾者對象,而後給鴨子新的功能(計算叫的次數)。裝飾器也要實現 Quackable接口,而且持有鴨子實例變量-被裝飾者,內部使用一個靜態變量保存叫的次數,當 quack()被調用的時候咱們就把調用委託給被裝飾的 Quackable對象,而且把叫的次數加 1。測試

/**
 * 裝飾器模式,發出叫聲的時候同時記錄次數.這樣咱們就沒必要修改每一個鴨子發出聲音的方法
 */
public class QuackCounter implements Quackable {

    private Quackable quack;

    private static AtomicInteger atomicInteger = new AtomicInteger(0);

    public QuackCounter(Quackable quack) {
        this.quack = quack;
    }

    @Override
    public void quack() {
        quack.quack();
        atomicInteger.incrementAndGet();
    }

    public static AtomicInteger getQuacks() {
        return atomicInteger;
    }
}複製代碼

利用裝飾器模式-咱們實現了不修改鴨子類卻又給鴨子新增了功能。接着咱們須要修改屏幕模擬器,將須要統計叫聲的鴨子包裝在裝飾器中。this

public class DuckSimulation {
    public static void main(String[] args) {
        DuckSimulation simulation = new DuckSimulation();
        simulation.simulate();
    }

    /**
     * 模擬屏幕展現功能
     */
    private void simulate() {
        // 使用裝飾器包裝鴨子
        Quackable redheadDuck = new QuackCounter(new RedheadDuck());
        Quackable mallarDuck = new QuackCounter(new MallarDuck());
        Quackable rubberDuck = new QuackCounter(new RubberDuck());
        Quackable duckCall = new QuackCounter(new DuckCall());
        //不想把天鵝的叫聲統計,因此不用裝飾器裝飾天鵝
        GooseAdapter gooseAdapter = new GooseAdapter(new Goose());
        System.out.println("使用裝飾器模式後,統計叫的次數,不包含天鵝");

        simulate(redheadDuck);
        simulate(mallarDuck);
        simulate(rubberDuck);
        simulate(duckCall);
        simulate(gooseAdapter);
        System.out.println("一共叫了 " + QuackCounter.getQuacks() + " 次");
    }

    private void simulate(Quackable quackable) {
        quackable.quack();
    }

}
複製代碼

抽象工廠

寫到這裏咱們已經用上了適配器模式、裝飾器模式。有沒有以爲咱們建立鴨子都是 new 出來的?爲何不把建立鴨子的的程序集合集中在一個地方,換句話說就是將建立於修飾的部分包裝起來。就是咱們接下來要說的:工廠模式。atom

咱們定義一個工廠,生產各類不一樣類型的鴨子產品家族,因此咱們使用抽象工廠模式。spa

首先從定義抽象工廠 AbstractDuckFactory開始,用於建立不一樣類型的鴨子家族。

/**
 * 抽象工廠模式,定義產品族
 */
public abstract class AbstractDuckFactory {
    public abstract Quackable createDuckCall();
    public abstract Quackable createMallarDuck();
    public abstract Quackable createRedheadDuck();
    public abstract Quackable createRubberDuck();
}複製代碼

接着建立一個普通鴨子工廠繼承抽象工廠,該工廠建立沒有裝飾器裝飾的鴨子。屏幕模擬器並不知道實際的產品是什麼,只知道它實現了 Quackable接口。把建立細節丟給工廠,而不是直接 new 建立,這也是控制反轉的思想,在 Spring 框架中大量出現。

/**
 * 每一個方法建立一種產品,一種特定種類的 Quackable
 */
public class DuckFactory extends AbstractDuckFactory {
    @Override
    public Quackable createDuckCall() {
        return new DuckCall();
    }

    @Override
    public Quackable createMallarDuck() {
        return new MallarDuck();
    }

    @Override
    public Quackable createRedheadDuck() {
        return new RedheadDuck();
    }

    @Override
    public Quackable createRubberDuck() {
        return new RubberDuck();
    }
}複製代碼

如今咱們要建立帶計數器叫聲功能的鴨子工廠DuckCountFactory,它持有DuckFactory 的一個實例用於建立普通鴨子並放進 QuackCounter裝飾器中從而得以建立帶計數器的鴨子。這裏其實也是用到了裝飾器模式。

/**
 * 叫聲計數器工廠:同時還結合了裝飾器模式,持有 工廠引用,包裝了duckFactory,從而加強了功能
 * 建立計數器鴨子
 */
public class DuckCountFactory extends AbstractDuckFactory {

    private AbstractDuckFactory duckFactory;

    public DuckCountFactory(DuckFactory duckFactory) {
        this.duckFactory = duckFactory;
    }

    @Override
    public Quackable createDuckCall() {
        return new QuackCounter(duckFactory.createDuckCall());
    }

    @Override
    public Quackable createMallarDuck() {
        return new QuackCounter(duckFactory.createMallarDuck());
    }

    @Override
    public Quackable createRedheadDuck() {
        return new QuackCounter(duckFactory.createRedheadDuck());
    }

    @Override
    public Quackable createRubberDuck() {
        return new QuackCounter(duckFactory.createRubberDuck());
    }
}複製代碼

既然工廠咱們定義好了,接下來就要修改屏幕模擬器代碼運用工廠來產生鴨子。咱們建立一個多態方法simulate(),此方法須要一個用來建立對象的工廠,傳入不一樣的工廠則生產不一樣的產品家族。

咱們把原來直接 new 產生鴨子的代碼改形成經過工廠建立,代碼以下。

public class DuckSimulation {
    public static void main(String[] args) {
        DuckSimulation simulation = new DuckSimulation();
        AbstractDuckFactory duckCountFactory = new DuckCountFactory(new DuckFactory());
        simulation.simulate(duckCountFactory);
    }

    /**
     * 模擬屏幕展現功能
     */
    private void simulate(AbstractDuckFactory duckFactory) {
        Quackable redheadDuck = duckFactory.createRedheadDuck();
        Quackable mallarDuck = duckFactory.createMallarDuck();
        Quackable rubberDuck = duckFactory.createRubberDuck();
        Quackable duckCall = duckFactory.createDuckCall();
        //不想把天鵝的叫聲統計,因此不用裝飾器裝飾
        GooseAdapter gooseAdapter = new GooseAdapter(new Goose());
        System.out.println("使用裝飾器模式後,統計叫的次數,不包含天鵝,同時使用了工廠模式產生鴨子");

        simulate(redheadDuck);
        simulate(mallarDuck);
        simulate(rubberDuck);
        simulate(duckCall);
        simulate(gooseAdapter);
        System.out.println("一共叫了 " + QuackCounter.getQuacks() + " 次");
    }

    private void simulate(Quackable quackable) {
        quackable.quack();
    }

}
複製代碼

組合模式-管理一羣鴨子

需求方又來了,他們想控制不一樣鴨子羣,把鴨子視爲一個集合,爲了知足可以管理不一樣鴨羣的需求。

還記得麼?組合模式容許咱們像對待單個對象同樣對待集合對象。因此利用組合模式管理一羣Quackable再適合不過了。

首先,組合須要和葉子節點元素同樣實現相同的接口。這裏的「葉節點」就是Quackable

咱們用一個 ArrayList保存屬於這個組合的Quackable對象,用add()方法新增Quackable對象到組合中。由於鴨羣也是Quackable,因此也具有quack()方法,該方法會對整個鴨羣產生做用。

/**
 * 組合模式,管理一羣鴨子: 對待單個對象同樣對待集合對象
 * 組合須要和葉子節點同樣實現相同的接口,這裏的葉子節點就是 Quackable
 */
public class Flock implements Quackable {

    private List<Quackable> quackers = new ArrayList<>();

    public void add(Quackable quackable) {
        quackers.add(quackable);
    }

    @Override
    public void quack() {
        for (Quackable quackable : quackers) {
            quackable.quack();
        }
    }
}複製代碼

咱們的組合好了,如今要修改模擬器實現鴨羣定義與管理,和以前同樣。

  1. 首先建立全部的Quackable對象。
  2. 在建立不一樣的組合Flock鴨羣,而後將對應的鴨子放入鴨羣。
  3. 最後就能根據組合的鴨羣分類測試鴨子滿屏飛以及控制不一樣的鴨羣行爲了。
public class DuckSimulation {
    public static void main(String[] args) {
        DuckSimulation simulation = new DuckSimulation();
        AbstractDuckFactory duckCountFactory = new DuckCountFactory(new DuckFactory());
        simulation.simulate(duckCountFactory);
    }

    /**
     * 模擬屏幕展現功能
     */
    private void simulate(AbstractDuckFactory duckFactory) {
        Quackable redheadDuck = duckFactory.createRedheadDuck();
        Quackable mallarDuck = duckFactory.createMallarDuck();
        Quackable rubberDuck = duckFactory.createRubberDuck();
        Quackable duckCall = duckFactory.createDuckCall();
        //不想把天鵝的叫聲統計,因此不用裝飾器裝飾
        GooseAdapter gooseAdapter = new GooseAdapter(new Goose());
        System.out.println("----使用裝飾器模式後,統計叫的次數,不包含天鵝,同時使用了工廠模式產生鴨子---");

        System.out.println("--使用組合模式管理鴨子羣--");
        // 主要鴨子羣
        Flock flockOfDucks = new Flock();

        flockOfDucks.add(redheadDuck);
        flockOfDucks.add(mallarDuck);
        flockOfDucks.add(rubberDuck);
        flockOfDucks.add(duckCall);
        flockOfDucks.add(gooseAdapter);
        // 綠頭鴨羣
        Flock mallarFlock = new Flock();

        Quackable mallarDuck1 = duckFactory.createMallarDuck();
        Quackable mallarDuck2 = duckFactory.createMallarDuck();
        Quackable mallarDuck3 = duckFactory.createMallarDuck();
        Quackable mallarDuck4 = duckFactory.createMallarDuck();
        mallarFlock.add(mallarDuck1);
        mallarFlock.add(mallarDuck2);
        mallarFlock.add(mallarDuck3);
        mallarFlock.add(mallarDuck4);

        System.out.println("----主要鴨子羣模擬器----");
        simulate(flockOfDucks);
        System.out.println("---綠頭鴨羣模擬---");
        simulate(mallarFlock);
        System.out.println("一共叫了 " + QuackCounter.getQuacks() + " 次");
    }

    private void simulate(Quackable quackable) {
        quackable.quack();
    }

}
複製代碼

觀察者模式-觀察特定鴨子叫

組合模式讓咱們很好的管理鴨羣,可是如今產品經理又有一個相反的需求:咱們也須要追蹤個別鴨子,當它呱呱叫鵝時候咱們可以收到通知。

同窗們是否是想到觀察和模式,當感興趣的某個事件發生的時候咱們就收到通知。就像咱們訂閱的公衆號發送消息,那麼就通知。

被觀察者QuackObservable

首先咱們須要定義被觀察者角色,提供「註冊觀察者」、「移除觀察者」、「通知觀察者」方法。任何想被觀察的Quackable都要實現該接口,任何註冊到QuackObservable的觀察者QuackObserver都會收到呱呱叫通知,曬後咱們會定義觀察者。

/**
 * 被觀察者:須要管理觀察者與通知觀察者
 */
public interface QuackObservable {
    /**
     * 註冊觀察者
     * @param observer
     */
    void registerObserver(QuackObserver observer);

    /**
     * 移除觀察者
     * @param observer
     */
    void removeObserver(QuackObserver observer);

    /**
     * 通知觀察者
     */
    void notifyObservers();
}
複製代碼

如今咱們須要把全部鴨子實現該接口成爲被觀察者,從而使得咱們能夠觀察呱呱叫。因此咱們乾脆讓Quackable來繼承QuackObservable接口。咱們必須確認全部實現Quackable的具體類可以扮演被觀察者角色。

/**
 * 呱呱叫接口,繼承被觀察者接口,讓全部實現了 Quackable 的實現類可以扮演被觀察者
 */
public interface Quackable extends QuackObservable {
    /**
     * 呱呱叫
     */
    void quack();
}複製代碼

ObservableDelegate輔助類

因爲全部的鴨子都實現了Quackable接口,而該接口又繼承了QuackObservable被觀察者接口。因此每一個鴨子類都須要實現註冊、通知、取消註冊的代碼。咱們不這麼幹,抽出一個輔助類ObservableDelegate封裝「註冊」、「通知」、「取消註冊」功能,而後和QuackObservable組合在一塊兒,這樣只須要一份代碼便可,QuackObservable的全部調用都委託到ObservableDelegate輔助類。

在構造方法中咱們傳入QuackObservable,好讓觀察者知道是哪一個對象在呱呱叫。

/**
 * 實現被觀察者接口,與 QuackObservable 組合在一塊兒,這樣咱們只須要一份代碼,QuackObservable 的全部調用都委託給
 * Observable 輔助類
 */
public class ObservableDelegate implements QuackObservable {

    private List<QuackObserver> observerList = new ArrayList<>();

    private QuackObservable duck;

    private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    public ObservableDelegate(QuackObservable duck) {
        this.duck = duck;
    }

    @Override
    public void registerObserver(QuackObserver observer) {
        ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
        writeLock.lock();
        try {
            observerList.add(observer);
        } finally {
            writeLock.unlock();
        }

    }

    @Override
    public void removeObserver(QuackObserver observer) {
        ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
        writeLock.lock();
        try {
            observerList.remove(observer);
        } finally {
            writeLock.unlock();
        }
    }

    @Override
    public void notifyObservers() {
        ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
        readLock.lock();
        try {
           //通知全部的觀察者
             observerList.forEach(item -> item.update(duck));
        } finally {
          readLock.unlock();
        }

    }
}
複製代碼

輔助類實現了全部必要的功能,咱們只要把它插進一個類就能夠將工做委託到 ObservableDelegate。

接下來咱們整合 ObservableDelegateQuackable使得 Quackable的註冊於通知都委託到輔助類。因此每一個Quackable的實現類都應該持有ObservableDelegate的實例。接下來咱們改造鴨子實現類。

public class MallarDuck implements Quackable {

    private QuackObservable observableDelegate;

    public MallarDuck() {
        this.observableDelegate = new ObservableDelegate(this);
    }

    @Override
    public void quack() {
        System.out.println("標準綠頭鴨呱呱叫...");
        //當呱呱叫的時候讓觀察者知道
        notifyObservers();
    }

    @Override
    public void registerObserver(QuackObserver observer) {
        observableDelegate.registerObserver(observer);
    }

    @Override
    public void removeObserver(QuackObserver observer) {
        observableDelegate.removeObserver(observer);
    }

    @Override
    public void notifyObservers() {
        observableDelegate.notifyObservers();
    }
}


/**
 * 鴨子叫模擬器
 */
public class DuckCall implements Quackable {

    /**
     * 持有 QuackObservable 的引用,將 委託給輔助類實現
     */
    private QuackObservable observableDelegate;

    public DuckCall() {
        // 委託給觀察者輔助類
        this.observableDelegate = new ObservableDelegate(this);
    }

    @Override
    public void quack() {
        System.out.println("鴨子模擬器叫...");
        //當呱呱叫的時候讓觀察者知道
        notifyObservers();
    }

    @Override
    public void registerObserver(QuackObserver observer) {
        observableDelegate.registerObserver(observer);
    }

    @Override
    public void removeObserver(QuackObserver observer) {
        observableDelegate.removeObserver(observer);
    }

    @Override
    public void notifyObservers() {
        observableDelegate.notifyObservers();
    }
}


public class RedheadDuck implements Quackable {

    private QuackObservable observableDelegate;

    public RedheadDuck() {
        this.observableDelegate = new ObservableDelegate(this);
    }
    @Override
    public void quack() {
        System.out.println("紅頭鴨呱呱叫...");
        //當呱呱叫的時候讓觀察者知道
        notifyObservers();
    }

    @Override
    public void registerObserver(QuackObserver observer) {
        observableDelegate.registerObserver(observer);
    }

    @Override
    public void removeObserver(QuackObserver observer) {
        observableDelegate.removeObserver(observer);
    }

    @Override
    public void notifyObservers() {
        observableDelegate.notifyObservers();
    }
}


/**
 * 橡皮鴨
 */
public class RubberDuck implements Quackable {

    private QuackObservable observableDelegate;

    public RubberDuck() {
        this.observableDelegate = new ObservableDelegate(this);
    }
    @Override
    public void quack() {
        System.out.println("橡皮鴨吱吱叫...");//當呱呱叫的時候讓觀察者知道
        notifyObservers();
    }

    @Override
    public void registerObserver(QuackObserver observer) {
        observableDelegate.registerObserver(observer);
    }

    @Override
    public void removeObserver(QuackObserver observer) {
        observableDelegate.removeObserver(observer);
    }

    @Override
    public void notifyObservers() {
        observableDelegate.notifyObservers();
    }
}
複製代碼

還有咱們的適配器、以及鴨子叫計數器也是都把被觀察者核心代碼功能調用委託給輔助類

/**
 * 將天鵝適配成鴨子
 */
public class GooseAdapter implements Quackable {
    /**
     * 持有被修飾的對象
     */
    private Goose goose;

    private QuackObservable observableDelegate;

    public GooseAdapter(Goose goose) {
        this.goose = goose;
        observableDelegate = new ObservableDelegate(this);
    }

    @Override
    public void quack() {
        goose.honk();
        //當呱呱叫的時候讓觀察者知道
        notifyObservers();
    }

    @Override
    public void registerObserver(QuackObserver observer) {
        observableDelegate.registerObserver(observer);
    }

    @Override
    public void removeObserver(QuackObserver observer) {
        observableDelegate.removeObserver(observer);
    }

    @Override
    public void notifyObservers() {
        observableDelegate.notifyObservers();
    }
}


/**
 * 裝飾器模式,發出叫聲的時候同時記錄次數.這樣咱們就沒必要修改每一個鴨子發出聲音的方法
 */
public class QuackCounter implements Quackable {

    private Quackable quack;

    private static AtomicInteger atomicInteger = new AtomicInteger(0);

    public QuackCounter(Quackable quack) {
        this.quack = quack;
    }

    @Override
    public void quack() {
        quack.quack();
        atomicInteger.incrementAndGet();
    }

    public static AtomicInteger getQuacks() {
        return atomicInteger;
    }

    @Override
    public void registerObserver(QuackObserver observer) {
        quack.registerObserver(observer);
    }

    @Override
    public void removeObserver(QuackObserver observer) {
        quack.removeObserver(observer);
    }

    @Override
    public void notifyObservers() {
        quack.notifyObservers();
    }
}
複製代碼

以及以前定義的鴨羣,假如咱們也想觀察鴨羣的叫通知,因此鴨羣也要變成被觀察者,同時將調用委託給

ObservableDelegate

public class Flock implements Quackable {

    private List<Quackable> quackers = new ArrayList<>();

    private QuackObservable observableDelegate;

    public void add(Quackable quackable) {
        quackers.add(quackable);
        observableDelegate = new ObservableDelegate(this);
    }

    @Override
    public void quack() {
        for (Quackable quackable : quackers) {
            quackable.quack();
        }
        notifyObservers();
    }

    @Override
    public void registerObserver(QuackObserver observer) {
        quackers.forEach(item -> item.registerObserver(observer));
        observableDelegate.registerObserver(observer);
    }

    @Override
    public void removeObserver(QuackObserver observer) {
        quackers.forEach(item -> item.removeObserver(observer));
        observableDelegate.removeObserver(observer);
    }

    @Override
    public void notifyObservers() {
        observableDelegate.notifyObservers();
    }
}
複製代碼

觀察者-QuackObserver

最後、咱們要準備觀察了,如今須要一些觀察者。首先就從定義QuackObserver接口開始,它只有一個方法update(QuackObservable duck),傳入的就是呱呱叫對象。

/**
 * 鴨子觀察者,當被通知的時候執行update
 */
public interface QuackObserver {
    /**
     * @param duck 正在呱呱叫的對象
     */
    void update(QuackObservable duck);
}複製代碼

如今咱們來實現一個觀察者觀察呱呱叫,當收到通知的時候咱們就打印下是誰叫的。

/**
 * 呱呱叫觀察者,觀察感興趣的鴨子
 */
public class Quackologist implements QuackObserver {
    @Override
    public void update(QuackObservable duck) {
        System.out.println("Quackologist: " + duck + " just quacked。");
    }
}複製代碼

屏幕模擬器

大功告成,咱們只要在模擬器上建立觀察者,並把觀察者註冊到感興趣的被觀察者中就實現了。

public class DuckSimulation {
    public static void main(String[] args) {
        DuckSimulation simulation = new DuckSimulation();
        AbstractDuckFactory duckCountFactory = new DuckCountFactory(new DuckFactory());
        simulation.simulate(duckCountFactory);
    }

    /**
     * 模擬屏幕展現功能
     */
    private void simulate(AbstractDuckFactory duckFactory) {
        Quackable redheadDuck = duckFactory.createRedheadDuck();
        Quackable mallarDuck = duckFactory.createMallarDuck();
        Quackable rubberDuck = duckFactory.createRubberDuck();
        Quackable duckCall = duckFactory.createDuckCall();
        //不想把天鵝的叫聲統計,因此不用裝飾器裝飾
        GooseAdapter gooseAdapter = new GooseAdapter(new Goose());
        System.out.println("----使用裝飾器模式後,統計叫的次數,不包含天鵝,同時使用了工廠模式產生鴨子---");

        System.out.println("--使用組合模式管理鴨子羣--");
        // 主要鴨子羣
        Flock flockOfDucks = new Flock();

        flockOfDucks.add(redheadDuck);
        flockOfDucks.add(mallarDuck);
        flockOfDucks.add(rubberDuck);
        flockOfDucks.add(duckCall);
        flockOfDucks.add(gooseAdapter);
        // 綠頭鴨羣
        Flock mallarFlock = new Flock();

        Quackable mallarDuck1 = duckFactory.createMallarDuck();
        Quackable mallarDuck2 = duckFactory.createMallarDuck();
        Quackable mallarDuck3 = duckFactory.createMallarDuck();
        Quackable mallarDuck4 = duckFactory.createMallarDuck();
        mallarFlock.add(mallarDuck1);
        mallarFlock.add(mallarDuck2);
        mallarFlock.add(mallarDuck3);
        mallarFlock.add(mallarDuck4);

        //觀察者模式觀察指定鴨子的叫,flockOfDucks 被觀察者註冊了 一個觀察者
        System.out.println("====觀察者模式 start===");
        flockOfDucks.registerObserver(new Quackologist());

        System.out.println("----主要鴨子羣模擬器----");
        simulate(flockOfDucks);
        System.out.println("---綠頭鴨羣模擬---");
        simulate(mallarFlock);
        System.out.println("一共叫了 " + QuackCounter.getQuacks() + " 次");
    }

    private void simulate(Quackable quackable) {
        quackable.quack();
    }

}
複製代碼

主要的改動就是

flockOfDucks.registerObserver(new Quackologist());建立觀察者,而且觀察 flockOfDucks這個鴨羣的呱呱叫狀況。

總結

最後咱們用這個例子主要是打開讀者的思惟,遇到不一樣場景根據設計模式的特性即可以將問題迎刃而解,並且代碼也變得優雅、高內聚低耦合,代碼也獲得了複用。

從一開始的鵝適配-「適配器模式」,再到爲鴨子叫計數功能加強使用「裝飾器模式」,接着建立不少鴨子。就想到了建立型模式「工廠模式」,爲了管理鴨羣-則想到了「組合模式」,最後想要觀察特定鴨子叫,便很快的使用了觀察者模式、同時還運用了「委託模式」使得註冊觀察的代碼複用。

若對使用到的設計模式不熟悉能夠閱讀歷史文章瞭解,歡迎你們提出意見以及指正。

關注公衆號JavaStorm,更多幹貨

JavaStorm

相關文章
相關標籤/搜索