設計模式之複合模式

使用模式最棒的方式,就是把他們從家裏找出來同其他模式展開交互。這就是複合模式。

我們將重訪SimUDuck鴨子模擬器中那些鴨子。

我們將從頭重建我們的鴨子模擬器。

首先,創建一個Quackable接口:

public interface Quackable {
	public void quack();

}

某些鴨子實現此接口:

public class MallardDuck implements Quackable{
	public void quack(){
		System.out.println("Quack");
	}

}

public class RedHeadDuck implements Quackable{
	public void quack(){
		System.out.println("Quack");
	}

}

public class DuckCall implements Quackable{
	public void quack(){
		System.out.println("Kwak");
	}

}
public class RubberDuck implements Quackable{
	public void quack(){
		System.out.println("Squeak");
	}

}


好了,有了鴨子,還需要一個模擬器:

public class DuckSimulator {
	public static void main(String[]args){
		DuckSimulator simulator=new DuckSimulator();
		simulator.simulate();
	}
	
	void simulate(){
		Quackable mallardDuck=new MallardDuck();
		Quackable redHeadDUck=new RedHeadDuck();
		Quackable duckCall=new DuckCall();
		Quackable rubberDuck=new RubberDuck();
		
		System.out.println("\nDuck Simulator");
		
		simulate(mallardDuck);
		simulate(redHeadDUck);
		simulate(duckCall);
		simulate(rubberDuck);
	}
	
	void simulate(Quackable duck){
		duck.quack();
	}

}

結果:

Duck Simulator
Quack
Quack
Kwak
Squeak


當鴨子出現在這裏,鵝應該在附近:

public class Goose {
	public void honk(){
		System.out.println("Honk");
	}

}

把鴨子和鵝摻合在一起,需要鵝適配器:

public class GooseAdapter implements Quackable{
	Goose goose;
	
	public GooseAdapter(Goose goose){
		this.goose=goose;
	}
	
	public void quack(){
		goose.honk();
	}

}

現在在模擬器中可以使用鵝了:

public class DuckSimulator {
	public static void main(String[]args){
		DuckSimulator simulator=new DuckSimulator();
		simulator.simulate();
	}
	
	void simulate(){
		Quackable mallardDuck=new MallardDuck();
		Quackable redHeadDUck=new RedHeadDuck();
		Quackable duckCall=new DuckCall();
		Quackable rubberDuck=new RubberDuck();
		Quackable gooseDuck=new GooseAdapter(new Goose());//把goose包裝成GooseAdapter
		
		System.out.println("\nDuck Simulator");
		
		simulate(mallardDuck);
		simulate(redHeadDUck);
		simulate(duckCall);
		simulate(rubberDuck);
		simulate(gooseDuck);
	}
	
	void simulate(Quackable duck){
		duck.quack();
	}

}

結果:

Duck Simulator
Quack
Quack
Kwak
Squeak
Honk

呱呱叫學家想要不變化鴨子類的情況下,計算呱呱叫的次數,我們可以創建一個裝飾者,通過把鴨子包裝進裝飾者對象,給鴨子一些新行爲:

public class QuackCounter implements Quackable{
	Quackable duck;
	static int numberOfQuacks;//靜態變量跟蹤所有呱呱叫次數
	
	public QuackCounter(Quackable duck){
		this.duck=duck;
	}
	
	public void quack(){
		duck.quack();
		numberOfQuacks++;
	}
	
	public static int getQuacks(){
		return numberOfQuacks;
	}

}

更新模擬器:

public class DuckSimulator {
	public static void main(String[]args){
		DuckSimulator simulator=new DuckSimulator();
		simulator.simulate();
	}
	
	void simulate(){
		Quackable mallardDuck=new QuackCounter(new MallardDuck());
		Quackable redHeadDUck=new QuackCounter( new RedHeadDuck());
		Quackable duckCall=new QuackCounter(new DuckCall());
		Quackable rubberDuck=new QuackCounter(new RubberDuck());
		Quackable gooseDuck=new GooseAdapter(new Goose());//我們不裝飾鵝
		
		System.out.println("\nDuck Simulator:with decorator");
		
		simulate(mallardDuck);
		simulate(redHeadDUck);
		simulate(duckCall);
		simulate(rubberDuck);
		simulate(gooseDuck);
		
		System.out.println("The ducks quacked "+QuackCounter.getQuacks()+" times");
	}
	
	void simulate(Quackable duck){
		duck.quack();
	}

}

結果:

Duck Simulator:with decorator
Quack
Quack
Kwak
Squeak
Honk
The ducks quacked 4 times

包裝對象纔有效果,沒包裝就沒效果,我們可以將創建和裝飾的部分包裝起來,工廠模式:

public abstract class AbstractDuckFactory {
	public abstract Quackable createMallardDuck();
	public abstract Quackable createRedHeadDuck();
	public abstract Quackable createDuckCall();
	public abstract Quackable createRubberDuck();

}

創建一個沒有裝飾者的工廠:

public class DuckFactory extends AbstractDuckFactory{

	@Override
	public Quackable createMallardDuck() {
		// TODO Auto-generated method stub
		return new MallardDuck();
	}

	@Override
	public Quackable createRedHeadDuck() {
		// TODO Auto-generated method stub
		return new RedHeadDuck();
	}

	@Override
	public Quackable createDuckCall() {
		// TODO Auto-generated method stub
		return new DuckCall();
	}

	@Override
	public Quackable createRubberDuck() {
		// TODO Auto-generated method stub
		return new RubberDuck();
	}
	
//模擬器並不知道實際產品是什麼,只知道實現了Quackable接口
}

創建我們想要的工廠:

public class CountingDuckFactory extends AbstractDuckFactory{

	@Override
	public Quackable createMallardDuck() {
		// TODO Auto-generated method stub
		return new QuackCounter(new MallardDuck());
	}

	@Override
	public Quackable createRedHeadDuck() {
		// TODO Auto-generated method stub
		return new QuackCounter(new RedHeadDuck());
	}

	@Override
	public Quackable createDuckCall() {
		// TODO Auto-generated method stub
		return new QuackCounter(new DuckCall());
	}

	@Override
	public Quackable createRubberDuck() {
		// TODO Auto-generated method stub
		return new QuackCounter(new RubberDuck());
	}

}

設置模擬器:

public class DuckSimulator {
	public static void main(String[]args){
		DuckSimulator simulator=new DuckSimulator();
		AbstractDuckFactory duckFactory=new CountingDuckFactory();
		simulator.simulate(duckFactory);
	}
	
	void simulate(AbstractDuckFactory duckFactory){
		Quackable mallardDuck=duckFactory.createMallardDuck();
		Quackable redHeadDUck=duckFactory.createRedHeadDuck();
		Quackable duckCall=duckFactory.createDuckCall();
		Quackable rubberDuck=duckFactory.createRubberDuck();
		Quackable gooseDuck=new GooseAdapter(new Goose());
		
		System.out.println("\nDuck Simulator:with abstract factory");
		
		simulate(mallardDuck);
		simulate(redHeadDUck);
		simulate(duckCall);
		simulate(rubberDuck);
		simulate(gooseDuck);
		
		System.out.println("The ducks quacked "+QuackCounter.getQuacks()+" times");
	}
	
	void simulate(Quackable duck){
		duck.quack();
	}

}

結果:

Duck Simulator:with abstract factory
Quack
Quack
Kwak
Squeak
Honk
The ducks quacked 4 times

現在管理員想管理一羣鴨子,而不是個別,我們可以用到組合模式:

public class Flock implements Quackable{
	ArrayList quackers=new ArrayList<>();
	
	public void add(Quackable quacker){
		quackers.add(quacker);
	}
	
	public void quack(){
		Iterator iterator=quackers.iterator();//迭代器模式
		while(iterator.hasNext()){
			Quackable quacker=(Quackable)iterator.next();
			quacker.quack();
		}
	}
	

}

修改模擬器:

public class DuckSimulator {
	public static void main(String[]args){
		DuckSimulator simulator=new DuckSimulator();
		AbstractDuckFactory duckFactory=new CountingDuckFactory();
		simulator.simulate(duckFactory);
	}
	
	void simulate(AbstractDuckFactory duckFactory){
		Quackable mallardDuck=duckFactory.createMallardDuck();
		Quackable redHeadDUck=duckFactory.createRedHeadDuck();
		Quackable duckCall=duckFactory.createDuckCall();
		Quackable rubberDuck=duckFactory.createRubberDuck();
		Quackable gooseDuck=new GooseAdapter(new Goose());
		
		System.out.println("\nDuck Simulator:with composite-flocks");
		
		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");
		simulate(flockOfDucks);//測試一整羣
		
		System.out.println("\nDuck Simulator:Mallard Flock Simulation");
		simulate(flockOfMallards);//測試綠頭鴨羣
		
		System.out.println("The ducks quacked "+QuackCounter.getQuacks()+" times");
	}
	
	void simulate(Quackable duck){
		duck.quack();
	}

}

結果:

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

管理員又有新的要求了,需要跟蹤個別的鴨子,我們可以用觀察者模式:

首先需要一個Observable接口;(這裏的Observable就是被觀察者)

public interface QuackObservable {
	
	public void registerObserver(Observer observer);
	public void notifyObservers();

}

需要確定所有的quackable都實現此接口:

public interface Quackable extends QuackObservable{
	public void quack();

}
確定所有實現Quackable的具體類都扮演QuackObservable的角色:

我們需要在每一個類中實現註冊和通知,這次我們要用稍微不一樣的做法:

我們要在另一個被稱爲Observable的類中封裝註冊和通知的代碼,然後將它和QuackObservable組合在一起。

Observer輔助類:

import java.util.ArrayList;
import java.util.Iterator;


public class Observable implements QuackObservable{
	ArrayList observers=new ArrayList<>();
	QuackObservable duck;
	
	public Observable(QuackObservable duck){
		this.duck=duck;
	}
	
	public void registerObserver(Observer observer){
		observers.add(observer);
	}
	
	public void notifyObservers(){
		Iterator iterator=observers.iterator();
		while(iterator.hasNext()){
			Observer observer=(Observer)iterator.next();
			observer.update(duck);
		}
 	}


}

整合Observable輔助類和Quackable類:

下面是MallardDuck實現,其他一樣

public class MallardDuck implements Quackable{
	Observable observable;
	
	public MallardDuck(){
		observable=new Observable(this);
	}
	
	public void quack(){
		System.out.println("Quack");
		notifyObservers();
	}

	@Override
	public void registerObserver(Observer observer) {
		// TODO Auto-generated method stub
		observable.registerObserver(observer);
	}

	@Override
	public void notifyObservers() {
		// TODO Auto-generated method stub
		observable.notifyObservers();
	}

}


QuackCOunter裝飾者

public class QuackCounter implements Quackable{
	Quackable duck;
	static int numberOfQuacks;//靜態變量跟蹤所有呱呱叫次數
	
	public QuackCounter(Quackable duck){
		this.duck=duck;
	}
	
	public void quack(){
		duck.quack();
		numberOfQuacks++;
	}
	
	public static int getQuacks(){
		return numberOfQuacks;
	}

	@Override
	public void registerObserver(Observer observer) {
		// TODO Auto-generated method stub
		duck.registerObserver(observer);
	}

	@Override
	public void notifyObservers() {
		// TODO Auto-generated method stub
		duck.notifyObservers();
	}

}

Observer端:

public interface Observer {
	public void update(QuackObservable duck);

}

public class Quackologist implements Observer{
	public void update(QuackObservable duck){
		System.out.println("Quackologist: "+duck+" just quacked.");
	}

}

如果要觀察整個羣的話:

public class Flock implements Quackable{
	ArrayList quackers=new ArrayList<>();
	
	public void add(Quackable quacker){
		quackers.add(quacker);
	}
	
	public void quack(){
		Iterator iterator=quackers.iterator();
		while(iterator.hasNext()){
			Quackable quacker=(Quackable)iterator.next();
			quacker.quack();
		}
	}

	@Override
	public void registerObserver(Observer observer) {
		// TODO Auto-generated method stub
		Iterator iterator=quackers.iterator();
		while(iterator.hasNext()){
			Quackable duck=(Quackable)iterator.next();
			duck.registerObserver(observer);
		}
	}

	@Override
	public void notifyObservers() {
		// TODO Auto-generated method stub
		
	}

	
	

}

更新模擬器:

public class DuckSimulator {
	public static void main(String[]args){
		DuckSimulator simulator=new DuckSimulator();
		AbstractDuckFactory duckFactory=new CountingDuckFactory();
		simulator.simulate(duckFactory);
	}
	
	void simulate(AbstractDuckFactory duckFactory){	
		
		System.out.println("\nDuck Simulator:with observer");
		
		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);
		
		
		Quackologist quackologist=new Quackologist();
		flockOfMallards.registerObserver(quackologist);
		simulate(flockOfMallards);
		
		System.out.println("The ducks quacked "+QuackCounter.getQuacks()+" times");
	}
	
	void simulate(Quackable duck){
		duck.quack();
	}

}

結果:

Duck Simulator:with observer
Quack
Quackologist: duck.MallardDuck@4aa0b07b just quacked.
Quack
Quackologist: duck.MallardDuck@7ba28183 just quacked.
Quack
Quackologist: duck.MallardDuck@69e4fede just quacked.
Quack
Quackologist: duck.MallardDuck@3918d722 just quacked.
The ducks quacked 4 times




這個例子主要的目的是展示許多模式可以合作,真實的設計過程中,不會想要這麼做,不然有點殺雞用牛刀的趕腳。


MVC模式是一個典型的複合模式。

MVC,即model-view-controller,比如一個MP3播放器底層就是MVC模式。

1、你是用戶,你和視圖交互。視圖是模型的窗口。

2、控制器要求模型狀態改變。

3、控制器也有可能要求視圖做改變。

4、模型狀態改變時,模型會通知視圖。

5、視圖向模型詢問狀態。

最典型的MVC就是JSP + servlet + javabean的模式.

從設計模式看,模型利用觀察者讓控制器和視圖可以隨最新的狀態改變而更新。另一方面,視圖和控制器則實現了策略模式。控制器是視圖的行爲,如果你希望不同的行爲,可以直接換一個控制器。視圖內部使用組合模式來管理窗口、按鈕以及其他顯示組件。






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