1. 程式人生 > >設計模式十一之複合模式(不同模式的組合使用Java)

設計模式十一之複合模式(不同模式的組合使用Java)

這是我看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模式