設計模式十一之複合模式(不同模式的組合使用Java)
阿新 • • 發佈:2018-12-09
這是我看Head first設計模式書籍之後想要總結的知識點,一方面是對自己學習的東西總結和提煉加強自己的理解和記憶,另一方面是給大家簡化這本書,方便大家快速瞭解各種設計模式。
我想提醒大家的是,設計模式只是前人總結的一些經驗套路,實際上還是要在開發專案中慢慢體會,不可成為設計模式的中毒患者,強行照搬設計模式的一些規則。
複合模式 有一些威力強大的OO設計同時使用多個設計模式,模式通常被一起使用,並被組合在同一個設計解決方案中 複合模式在一個解決方案中結合兩個或多個模式,以解決一般或重複的問題,最常見的複合模式就是MVC(模型檢視控制器 Model-View-Controller)
我們將介紹一個鴨子的程式,會用到各種不同的模式,以便更加深刻理解實際應用
//建立一個Quackable介面,賦予具體類呱呱叫的能力 package com.gougoucompany.designpattern.compoundfirst; public interface Quackable { public void quack(); } //紅頭鴨和綠頭鴨具體實現 package com.gougoucompany.designpattern.compoundfirst; public class MallardDuck implements Quackable{ public void quack() { System.out.println("Quack"); } } package com.gougoucompany.designpattern.compoundfirst; public class RedheadDuck implements Quackable{ public void quack() { System.out.println("Quack"); } } //鴨鳴器和橡皮鴨(呱呱叫、吱吱叫) package com.gougoucompany.designpattern.compoundfirst; public class DuckCall implements Quackable{ public void quack() { System.out.println("Kwak"); } } package com.gougoucompany.designpattern.compoundfirst; public class RubberDuck implements Quackable{ public void quack() { System.out.println("Squeak"); } } //主類 package com.gougoucompany.designpattern.compoundfirst; //主類,產生鴨子,鴨子叫的模擬器方法 public class DuckSimulator { public static void main(String args[]) { DuckSimulator simulator = new DuckSimulator(); simulator.simulator(); } void simulator() { Quackable mallardDuck = new MallardDuck(); Quackable redheadDuck = new RedheadDuck(); Quackable rubberDuck = new RubberDuck(); Quackable duckCall = new DuckCall(); System.out.println("\nDuck Simulator"); simulator(mallardDuck); simulator(redheadDuck); simulator(rubberDuck); simulator(duckCall); } void simulator(Quackable duck) { duck.quack(); } } /* result: Duck Simulator Quack Quack Squeak Kwak */ //鵝,咯咯叫 package com.gougoucompany.designpattern.compoundfirst; public class Goose { public void honk() { System.out.println("Honk"); } } //鵝和鴨子都會叫,我們為了在模擬器中使用鵝,可以使用介面卡模式,將鵝適配成鴨子 package com.gougoucompany.designpattern.compoundfirst; //介面卡會實現目標介面 public class GooseAdapter implements Quackable { Goose goose; //構造器要傳入要適配的鵝物件 public GooseAdapter(Goose goose) { this.goose = goose; } //當呼叫quack()時,會委託到鵝的honk()方法 @Override public void quack() { goose.honk(); } } //現在我們更改主類DuckSimulator package com.gougoucompany.designpattern.compoundfirst; //主類,產生鴨子,鴨子叫的模擬器方法 public class DuckSimulator { public static void main(String args[]) { DuckSimulator simulator = new DuckSimulator(); simulator.simulator(); } void simulator() { Quackable mallardDuck = new MallardDuck(); Quackable redheadDuck = new RedheadDuck(); Quackable rubberDuck = new RubberDuck(); Quackable duckCall = new DuckCall(); Quackable gooseDuck = new GooseAdapter(new Goose()); //通過介面卡可以讓鵝和鴨子一樣 System.out.println("\nDuck Simulator"); simulator(mallardDuck); simulator(redheadDuck); simulator(rubberDuck); simulator(duckCall); simulator(gooseDuck); } void simulator(Quackable duck) { duck.quack(); } } /* result: Duck Simulator Quack Quack Squeak Kwak Honk */ /*我們想在一群鴨子中,計算鴨子呱呱叫的次數,如何在不變化鴨子類的情況下,計算呱呱叫的次數 我們需要建立一個裝飾者,通過把鴨子包裝進裝飾者物件,給鴨子一些新的行為(計算呱呱叫的次數的行為,而不需要修改鴨子的程式碼) */ package com.gougoucompany.designpattern.compoundfirst; //需要實現目標介面,QuackCounter是一個裝飾者 public class QuackCounter implements Quackable { Quackable duck; //用一個例項變數來記錄被裝飾的呱呱叫者 static int numberOfQuacks; //靜態變數跟蹤所有的呱呱叫的次數 //將被裝飾者傳入構造器 public QuackCounter(Quackable duck) { this.duck = duck; } @Override public void quack() { duck.quack(); numberOfQuacks++; } public static int getQuacks() { return numberOfQuacks; } } //現在修改主類 package com.gougoucompany.designpattern.compoundfirst; //主類,產生鴨子,鴨子叫的模擬器方法 public class DuckSimulator { public static void main(String args[]) { DuckSimulator simulator = new DuckSimulator(); simulator.simulator(); } void simulator() { Quackable mallardDuck = new QuackCounter(new MallardDuck()); Quackable redheadDuck = new QuackCounter(new RedheadDuck()); Quackable rubberDuck = new QuackCounter(new RubberDuck()); Quackable duckCall = new QuackCounter(new DuckCall()); Quackable gooseDuck = new GooseAdapter(new Goose()); //通過介面卡可以讓鵝和鴨子一樣 不計入鵝的叫聲,因此不被裝飾 System.out.println("\nDuck Simulator: With Decorator"); simulator(mallardDuck); simulator(redheadDuck); simulator(rubberDuck); simulator(duckCall); simulator(gooseDuck); System.out.println("The ducks quacked " + QuackCounter.getQuacks() + " times"); } void simulator(Quackable duck) { duck.quack(); } } /* result: Duck Simulator: With Decorator Quack Quack Squeak Kwak Honk The ducks quacked 4 times */ /* 工廠模式: 我們看到鴨子物件必須被裝飾者裝飾之後才可以獲得計數的行為,我們現在將建立鴨子和裝飾鴨子兩部分包裝起來 需要保證每個鴨子都是被裝飾者裝飾過的,因此我們要建立一個工廠,建立裝飾過的鴨子,這個工廠要生產各種不同型別 的鴨子的產品家族,因此要用抽象工廠模式 */ //抽象工廠 package com.gougoucompany.designpattern.compoundfirst; /* 工廠模式: 我們看到鴨子物件必須被裝飾者裝飾之後才可以獲得計數的行為,我們現在將建立鴨子和裝飾鴨子兩部分包裝起來 需要保證每個鴨子都是被裝飾者裝飾過的,因此我們要建立一個工廠,建立裝飾過的鴨子,這個工廠要生產各種不同型別 的鴨子的產品家族,因此要用抽象工廠模式 */ //抽象工廠 public abstract class AbstractDuckFactory { public abstract Quackable createMallardDuck(); public abstract Quackable createRedheadDuck(); public abstract Quackable createDuckCall(); public abstract Quackable createRubberDuck(); } //此工廠建立沒有裝飾者的鴨子 package com.gougoucompany.designpattern.compoundfirst; public class DuckFactory extends AbstractDuckFactory { /** * 每個方法建立一個產品,一種特定種類的Quackable */ @Override public Quackable createMallardDuck() { return new MallardDuck(); } @Override public Quackable createRedheadDuck() { return new RedheadDuck(); } @Override public Quackable createDuckCall() { return new DuckCall(); } @Override public Quackable createRubberDuck() { return new RubberDuck(); } } //此工廠建立被裝飾過的鴨子產品 CountingDuckFactory擴充套件自抽象工廠 package com.gougoucompany.designpattern.compoundfirst; public class CountingDuckFactory extends AbstractDuckFactory{ @Override public Quackable createMallardDuck() { return new QuackCounter(new MallardDuck()); } @Override public Quackable createRedheadDuck() { return new QuackCounter(new RedheadDuck()); } @Override public Quackable createDuckCall() { return new QuackCounter(new DuckCall()); } @Override public Quackable createRubberDuck() { return new QuackCounter(new RubberDuck()); } } //修改主類 package com.gougoucompany.designpattern.compoundfirst; //主類,產生鴨子,鴨子叫的模擬器方法 public class DuckSimulator { public static void main(String args[]) { DuckSimulator simulator = new DuckSimulator(); //首先,建立工廠,準備把它傳入simulate()方法 AbstractDuckFactory duckFactory = new CountingDuckFactory(); simulator.simulator(duckFactory); } /** * 此方法需要一個AbstractDuckFactory引數,利用它建立鴨子,通過傳入 * 不同的工廠,就會得到不同的產品家族 * <p>Title: simulator</p> * <p>Description: </p> */ void simulator(AbstractDuckFactory duckFactory) { Quackable mallardDuck = duckFactory.createMallardDuck(); Quackable redheadDuck = duckFactory.createRedheadDuck(); Quackable rubberDuck = duckFactory.createRubberDuck(); Quackable duckCall = duckFactory.createDuckCall(); Quackable gooseDuck = new GooseAdapter(new Goose()); //通過介面卡可以讓鵝和鴨子一樣 不計入鵝的叫聲,因此不被裝飾 System.out.println("\nDuck Simulator: With Abstract Factory"); simulator(mallardDuck); simulator(redheadDuck); simulator(rubberDuck); simulator(duckCall); simulator(gooseDuck); System.out.println("The ducks quacked " + QuackCounter.getQuacks() + " times"); } void simulator(Quackable duck) { duck.quack(); } } /* result: Duck Simulator: With Abstract Factory Quack Quack Squeak Kwak Honk The ducks quacked 4 times */ /* 迭代器模式與組合模式 組合模式允許我們像對待單個物件一樣對待物件集合 如果要管理這些鴨子,我們需要將鴨子視為一個集合,甚至是子集合(subcollection),我們可以用組合模式來完成 也就是說客戶可以呼叫同一個方法來管理所有的不同種群的鴨子 */ package com.gougoucompany.designpattern.compoundfirst; import java.util.ArrayList; import java.util.Iterator; //組合需要和葉節點元素一樣實現相同的介面(這樣方法才能遞迴呼叫,並且呼叫一次就可以了) public class Flock implements Quackable { ArrayList<Quackable> quackers = new ArrayList<>(); /** * 在之前專門講解組合模式的選單和選單項中,我們有一組相同的方法,也包括add()方法 * 設計的好處是葉節點和組合之間是"透明的",你無需判斷到底是選單項還是選單。這裡 * 我們將Flock只有add()方法,Duck沒有add()方法,因為新增東西是沒有意義的,但是 * 透明性比較差,客戶如果想要呼叫add(),得先確定該Quackable物件是Flock才行。 * 所以折中考慮吧! * <p>Title: add</p> * <p>Description: </p> * @param quacker */ public void add(Quackable quacker) { quackers.add(quacker); } //群體鳴叫,呱呱呱 @Override public void quack() { Iterator<Quackable> iterator = quackers.iterator(); //這裡使用了迭代器模式 while(iterator.hasNext()) { Quackable quacker = (Quackable) iterator.next(); quacker.quack(); } } } //修改主類 package com.gougoucompany.designpattern.compoundfirst; //主類,產生鴨子,鴨子叫的模擬器方法 public class DuckSimulator { public static void main(String args[]) { DuckSimulator simulator = new DuckSimulator(); //首先,建立工廠,準備把它傳入simulate()方法 AbstractDuckFactory duckFactory = new CountingDuckFactory(); simulator.simulator(duckFactory); } /** * 此方法需要一個AbstractDuckFactory引數,利用它建立鴨子,通過傳入 * 不同的工廠,就會得到不同的產品家族 * <p>Title: simulator</p> * <p>Description: </p> */ void simulator(AbstractDuckFactory duckFactory) { //建立Quackable物件 Quackable redheadDuck = duckFactory.createRedheadDuck(); Quackable rubberDuck = duckFactory.createRubberDuck(); Quackable duckCall = duckFactory.createDuckCall(); Quackable gooseDuck = new GooseAdapter(new Goose()); //通過介面卡可以讓鵝和鴨子一樣 不計入鵝的叫聲,因此不被裝飾 System.out.println("\nDuck Simulator: With composite - Flocks"); //建立一個Flock,然後把一些Quackable塞給他,Flock是主群 Flock flockOfDucks = new Flock(); flockOfDucks.add(redheadDuck); flockOfDucks.add(rubberDuck); flockOfDucks.add(duckCall); flockOfDucks.add(gooseDuck); Flock flockOfMallards = new Flock(); //建立綠頭鴨小家族 Quackable mallardOne = duckFactory.createMallardDuck(); Quackable mallardTwo = duckFactory.createMallardDuck(); Quackable mallardThree = duckFactory.createMallardDuck(); Quackable mallardFour = duckFactory.createMallardDuck(); flockOfMallards.add(mallardOne); flockOfMallards.add(mallardTwo); flockOfMallards.add(mallardThree); flockOfMallards.add(mallardFour); flockOfDucks.add(flockOfMallards); //將綠頭鴨群加入主群 //測試一整群 System.out.println("\nDuck Simulator: Whole Flock Simulation"); simulator(flockOfDucks); //只測試綠頭鴨群 System.out.println("\nDuck Simulator: Mallard Flock Simulation"); simulator(flockOfMallards); System.out.println("The ducks quacked " + QuackCounter.getQuacks() + " times"); } void simulator(Quackable duck) { duck.quack(); } } /* result: Duck Simulator: With composite - Flocks Duck Simulator: Whole Flock Simulation Quack Squeak Kwak Honk Quack Quack Quack Quack Duck Simulator: Mallard Flock Simulation Quack Quack Quack Quack The ducks quacked 11 times */ /* 觀察者模式 我們現在需要追蹤個別的鴨子,有一個模式可以觀察物件的行為: 觀察者模式 */ package com.gougoucompany.designpattern.compoundfirst; /* * Observable就是被觀察的物件,需要註冊刪除和通知觀察者的方法,這裡簡單起見我們只加入註冊和通知觀察者方法 * QuackObservable是一個介面,任何想被觀察的Quackable都必須實現QuackObservable介面 */ public interface QuackObservable { /** * 具有註冊觀察者的方法,任何實現了Observer介面的觀察者都可以監聽呱呱叫 * <p>Title: registerObserver</p> * <p>Description: </p> * @param observer */ public void registerObserver(Observer observer); public void notifyObservers(); //通知觀察者的方法 } //讓所有的鴨子都實現觀察者介面,因此我們只需要將Quackable介面繼承QuackObservable package com.gougoucompany.designpattern.compoundfirst; //我們將介紹一個鴨子的程式,會用到各種不同的模式,以便更加深刻理解實際應用 //建立一個Quackable介面,賦予具體類呱呱叫的能力 public interface Quackable extends QuackObservable{ public void quack(); } /* 需要在實現Quackable介面的具體類中實現具體的成為被觀察者的抽象方法 但是我們要實現的被觀察者的抽象方法都是相同的,因此我們將QuackObservable所有的呼叫都委託給 Observable輔助類 */ //Observable輔助類,實現了所有必要的功能,將其插入一個類,就可以讓該類將工作委託給Observable package com.gougoucompany.designpattern.compoundfirst; import java.util.ArrayList; import java.util.Iterator; public class Observable implements QuackObservable { ArrayList<Observer> observers = new ArrayList<>(); //儲存所有的觀察者物件 QuackObservable duck; //被觀察者物件 public Observable(QuackObservable duck) { this.duck = duck; //需要記錄當前是哪個被觀察者物件在呱呱叫 } //註冊觀察者的程式碼 @Override public void registerObserver(Observer observer) { observers.add(observer); } //通知觀察者的程式碼 @Override public void notifyObservers() { Iterator<Observer> iterator = observers.iterator(); while(iterator.hasNext()) { Observer observer = iterator.next(); observer.update(duck); } } } //讓所有鴨子具體類(所有繼承Quackble的具體類,鴨子,被裝飾者裝飾的鴨子,或群)實現被觀察者介面,這裡其實我覺得可以用繼承的方式來實現程式碼更加簡潔一些 //紅頭鴨 package com.gougoucompany.designpattern.compoundfirst; public class RedheadDuck implements Quackable{ Observable observable; public RedheadDuck() { observable = new Observable(this); } @Override public void quack() { System.out.println("Quack"); notifyObservers(); } @Override public void registerObserver(Observer observer) { observable.registerObserver(observer); } @Override public void notifyObservers() { observable.notifyObservers(); } } //橡皮鴨 package com.gougoucompany.designpattern.compoundfirst; public class RubberDuck implements Quackable{ Observable observable; public RubberDuck() { observable = new Observable(this); } public void quack() { System.out.println("Squeak"); notifyObservers(); } @Override public void registerObserver(Observer observer) { observable.registerObserver(observer); } @Override public void notifyObservers() { observable.notifyObservers(); } } //綠頭鴨 package com.gougoucompany.designpattern.compoundfirst; public class MallardDuck implements Quackable{ Observable observable; public MallardDuck() { observable = new Observable(this); //構造器中傳入被觀察者的引用 } public void quack() { System.out.println("Quack"); notifyObservers(); //被觀察者發生呱呱叫行為就通知所有註冊的觀察者 } public void registerObserver(Observer observer) { observable.registerObserver(observer); } @Override public void notifyObservers() { observable.notifyObservers(); } } //鴨鳴器 package com.gougoucompany.designpattern.compoundfirst; public class DuckCall implements Quackable{ Observable observable; public DuckCall() { observable = new Observable(this); } public void quack() { System.out.println("Kwak"); notifyObservers(); } @Override public void registerObserver(Observer observer) { observable.registerObserver(observer); } @Override public void notifyObservers() { observable.notifyObservers(); } } //鵝適配成鴨子 鵝介面卡 package com.gougoucompany.designpattern.compoundfirst; //鵝和鴨子都會叫,我們為了在模擬器中使用鵝,可以使用介面卡模式,將鵝適配成鴨子 //介面卡會實現目標介面 public class GooseAdapter implements Quackable { Observable observable; Goose goose; //構造器要傳入要適配的鵝物件 public GooseAdapter(Goose goose) { this.goose = goose; observable = new Observable(this); } //當呼叫quack()時,會委託到鵝的honk()方法 @Override public void quack() { goose.honk(); notifyObservers(); } @Override public void registerObserver(Observer observer) { observable.registerObserver(observer); } @Override public void notifyObservers() { observable.notifyObservers(); } } //實現Flock和QuackCounter,讓他們實現QuackObservable介面,成為被觀察者 package com.gougoucompany.designpattern.compoundfirst; /*我們想在一群鴨子中,計算鴨子呱呱叫的次數,如何在不變化鴨子類的情況下,計算呱呱叫的次數 我們需要建立一個裝飾者,通過把鴨子包裝進裝飾者物件,給鴨子一些新的行為(計算呱呱叫的次數的行為,而不需要修改鴨子的程式碼) */ //需要實現目標介面,QuackCounter是一個裝飾者 public class QuackCounter implements Quackable { Quackable duck; //用一個例項變數來記錄被裝飾的呱呱叫者 static int numberOfQuacks; //靜態變數跟蹤所有的呱呱叫的次數 //將被裝飾者傳入構造器 public QuackCounter(Quackable duck) { this.duck = duck; } @Override public void quack() { duck.quack(); //當呼叫quack()方法,鴨子鳴叫,因為鴨子具體類已經在quack()中呼叫了通知觀察者的方法,因此不需要在此方法中新增 numberOfQuacks++; } public static int getQuacks() { return numberOfQuacks; } /** * 被裝飾者裝飾的鴨子也實現了Quackable介面,所以也是被觀察者QuackObservable */ @Override public void registerObserver(Observer observer) { duck.registerObserver(observer); } @Override public void notifyObservers() { duck.notifyObservers(); } } package com.gougoucompany.designpattern.compoundfirst; import java.util.ArrayList; import java.util.Iterator; /* 迭代器模式與組合模式 組合模式允許我們像對待單個物件一樣對待物件集合 如果要管理這些鴨子,我們需要將鴨子視為一個集合,甚至是子集合(subcollection),我們可以用組合模式來完成 也就是說客戶可以呼叫同一個方法來管理所有的不同種群的鴨子 */ //組合需要和葉節點元素一樣實現相同的介面(這樣方法才能遞迴呼叫,並且呼叫一次就可以了) public class Flock implements Quackable { ArrayList<Quackable> quackers = new ArrayList<>(); /** * 在之前專門講解組合模式的選單和選單項中,我們有一組相同的方法,也包括add()方法 * 設計的好處是葉節點和組合之間是"透明的",你無需判斷到底是選單項還是選單。這裡 * 我們將Flock只有add()方法,Duck沒有add()方法,因為新增東西是沒有意義的,但是 * 透明性比較差,客戶如果想要呼叫add(),得先確定該Quackable物件是Flock才行。 * 所以折中考慮吧! * <p>Title: add</p> * <p>Description: </p> * @param quacker */ public void add(Quackable quacker) { quackers.add(quacker); } //群體鳴叫,呱呱呱 @Override public void quack() { Iterator<Quackable> iterator = quackers.iterator(); //這裡使用了迭代器模式 while(iterator.hasNext()) { Quackable quacker = (Quackable) iterator.next(); quacker.quack(); } } /** * 如果我們觀察一個組合,就等於觀察我們組合內的所有東西,因此,當你註冊要觀察某個群(flock), * 就等於註冊要觀察所有的孩子,這甚至還包括另一個群(鴨子主群中有鴨子群也有鴨子) * 當向Flock註冊觀察者時,其實等於向Flock中的所有Quackable註冊觀察者,不管是一個鴨子還是一群鴨子 */ @Override public void registerObserver(Observer observer) { Iterator<Quackable> iterator = quackers.iterator(); while(iterator.hasNext()) { Quackable duck = (Quackable) iterator.next(); //可能是一個群,也可能是一個鴨子 //如果是一個群,則會深度遞迴,直到所有子節點都註冊完成觀察者 duck.registerObserver(observer); } } //這裡每個鴨子都實現了這個方法,因此可以為空 @Override public void notifyObservers() { } } //觀察者介面和觀察者 package com.gougoucompany.designpattern.compoundfirst; //觀察者介面,只有一個抽象方法update(),需要傳入正在呱呱叫的物件(QuackObservable) public interface Observer { public void update(QuackObservable duck); } package com.gougoucompany.designpattern.compoundfirst; //觀察者繼承Observer介面 package com.gougoucompany.designpattern.compoundfirst; //觀察者繼承Observer介面 public class Quackologist implements Observer { @Override public void update(QuackObservable duck) { System.out.println("Quackologist: " + duck.getClass().getSimpleName() + " just quacked."); } } //修改主類DuckSimulator package com.gougoucompany.designpattern.compoundfirst; //主類,產生鴨子,鴨子叫的模擬器方法 public class DuckSimulator { public static void main(String args[]) { DuckSimulator simulator = new DuckSimulator(); //首先,建立工廠,準備把它傳入simulate()方法 AbstractDuckFactory duckFactory = new CountingDuckFactory(); simulator.simulator(duckFactory); } /** * 此方法需要一個AbstractDuckFactory引數,利用它建立鴨子,通過傳入 * 不同的工廠,就會得到不同的產品家族 * <p>Title: simulator</p> * <p>Description: </p> */ void simulator(AbstractDuckFactory duckFactory) { //建立Quackable物件 Quackable redheadDuck = duckFactory.createRedheadDuck(); Quackable rubberDuck = duckFactory.createRubberDuck(); Quackable duckCall = duckFactory.createDuckCall(); //這裡鵝沒有被QuackCounter所修飾,因此不加入計數 Quackable gooseDuck = new GooseAdapter(new Goose()); //通過介面卡可以讓鵝和鴨子一樣 不計入鵝的叫聲,因此不被裝飾 //建立一個Flock,然後把一些Quackable塞給他,Flock是主群 Flock flockOfDucks = new Flock(); flockOfDucks.add(redheadDuck); flockOfDucks.add(rubberDuck); flockOfDucks.add(duckCall); flockOfDucks.add(gooseDuck); Flock flockOfMallards = new Flock(); //建立綠頭鴨小家族 Quackable mallardOne = duckFactory.createMallardDuck(); Quackable mallardTwo = duckFactory.createMallardDuck(); Quackable mallardThree = duckFactory.createMallardDuck(); Quackable mallardFour = duckFactory.createMallardDuck(); flockOfMallards.add(mallardOne); flockOfMallards.add(mallardTwo); flockOfMallards.add(mallardThree); flockOfMallards.add(mallardFour); flockOfDucks.add(flockOfMallards); System.out.println("\nDuck Simulator: With Observer"); Quackologist quackologist = new Quackologist(); //觀察者 flockOfDucks.registerObserver(quackologist); //將quackologist註冊成為一個群的觀察者 simulator(flockOfDucks); System.out.println("The ducks quacked " + QuackCounter.getQuacks() + " times"); } void simulator(Quackable duck) { duck.quack(); } } /* result: Duck Simulator: With Observer Quack Quackologist: RedheadDuck just quacked. Squeak Quackologist: RubberDuck just quacked. Kwak Quackologist: DuckCall just quacked. Honk Quackologist: GooseAdapter just quacked. Quack Quackologist: MallardDuck just quacked. Quack Quackologist: MallardDuck just quacked. Quack Quackologist: MallardDuck just quacked. Quack Quackologist: MallardDuck just quacked. The ducks quacked 7 times 這裡一共計數7次,因為鵝沒有被QuackCounter所修飾,因此沒有鳴叫次數計數的行為 */
下次我們將介紹真正的複合模式MVC模式