2008-04-01

设计模式学习之复合模式(2)

关键字: 设计模式

接上篇------>设计模式学习之复合模式(1)

 

我们为什么不将创建鸭子的程序集中在一个地方呢?换句话说,让我们将创建和装饰的部分包装起来,这看起来像是什么模式?
10.我们需要一些质量控制来确保鸭子一定是被包装起来的,需要建造一个工厂创建装饰过的鸭子.此工厂应该生产各种不同类型的鸭子的产品家族,使用我们使用抽象工厂模式.

//定义一个抽象工厂,它的子类会创建不同的家族
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 {
	//每个方法创建一个产品,一种特定种类的Quackable.
	//模拟器并不知道实际的产品是什么,只知道它实现了Quackable接口
	public Quackable createMallardDuck() {
		return new MallardDuck();
	}
	public Quackable createRedheadDuck() {
		return new RedheadDuck();
	}
	public Quackable createDuckCall() {
		return new DuckCall();
	}
	public Quackable createRubberDuck() {
		return new RubberDuck();
	}
}
//现在,要创建我们真正需要的工厂
public class CountingDuckFactory extends AbstractDuckFactory {
	//每个方法都会先用叫声计数装饰者将Quackable包装进来.模拟器并不知道有何不同,
	//只知道它实现了Quackable接口,所有的叫声都会被计算进去
	public Quackable createMallardDuck() {
		return new QuackCounter(new MallardDuck());
	}
	public Quackable createRedheadDuck() {
		return new QuackCounter(new RedheadDuck());
	}
	public Quackable createDuckCall() {
		return new QuackCounter(new DuckCall());
	}
	public Quackable createRubberDuck() {
		return new QuackCounter(new RubberDuck());
	}
}

 

11.我们修改模拟器来使用这个工厂

public class DuckSimulator {
	public static void main(String[] args) {
		DuckSimulator simulator = new DuckSimulator();
		//首先我们创建工厂,准备把它传入simulate方法
		AbstractDuckFactory duckFactory = new CountingDuckFactory();
		simulator.simulate(duckFactory);
	}
	//simulate需要一个AbstractDuckFactory参数,利用它来创建鸭子,而不是直接实例化鸭子
	void simulate(AbstractDuckFactory duckFactory) {
		Quackable redheadDuck = duckFactory.createMallardDuck();
		Quackable redheadDuck = duckFactory.createRedheadDuck();
		Quackable duckCall = duckFactory.createDuckCall();
		Quackable rubberDuck = duckFactory.createRubberDuck();
		Quackable gooseDuck = new GooseAdapter(new Goose());
		//这里不改动
		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();
	}
}

 

测试...
看到这里,你不觉得分别管理这些不同的鸭子变得有些困难吗?有什么办法帮我们作为一个整体来管理这些鸭子,甚至让我们管理几个想持续追踪的鸭子家族吗?下一次命令就能够让整个集合的鸭子听命行事,什么模式可以帮我们?
还记得吗,组合模式允许我们像对待单个对象一样对待对象集合.
12.让我们创建一群鸭子,实际上是一群Quackable

//别忘了,组合需要和叶节点元素一样实现相同的接口,这里的叶节点就是'Quackable'
public class Flock implements Quackable {
	//在每个flock内,我们使用ArrayList记录属于这个flock的Quackable对象
	ArrayList quackers = new ArrayList();
	//用add方法新增Quackable对象到flock
	public void add(Quackable quacker) {
		quackers.add(quacker);
	}
	//注意到了吗,这里我们其实还使用了迭代器模式
	public void quack() {
		Iterator iterator = quackers.iterator();
		while (iterator.hasNext()) {
			Quackable quacker = (Quackable)iterator.next();
			//毕竟flock也是Quackable,所以也要具备quack方法,此方法会对整群产生作用
			//我们遍历ArrayList调用每个元素上的quack方法
			quacker.quack();
		}
	}
}

 

13.我们的组合已经准备好了,我们需要一些让鸭子能进入组合的代码,再来修改模拟器

public class DuckSimulator {
	public static void main(String[] args) {
		DuckSimulator simulator = new DuckSimulator();
		//首先我们创建工厂,准备把它传入simulate方法
		AbstractDuckFactory duckFactory = new CountingDuckFactory();
		simulator.simulate(duckFactory);
	}
	//simulate需要一个AbstractDuckFactory参数,利用它来创建鸭子,而不是直接实例化鸭子
	void simulate(AbstractDuckFactory duckFactory) {
		Quackable redheadDuck = duckFactory.createRedheadDuck();
		Quackable duckCall = duckFactory.createDuckCall();
		Quackable rubberDuck = duckFactory.createRubberDuck();
		Quackable gooseDuck = new GooseAdapter(new Goose());
		
		//我们先创建一个flock,然后把许多Quackable塞给它,这个flock是主群
		Flock flockOfDucks = new Flock();
		flockOfDucks.add(redheadDuck);
		flockOfDucks.add(duckCall);
		flockOfDucks.add(rubberDuck);
		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);
		//测试整群
		simulate(flockOfDucks);
		//只测试绿头鸭群
		simulate(flockOfMallards);
		//最后显示呱呱叫次数
		System.out.println("\nThe ducks quacked " + 
		                   QuackCounter.getQuacks() + 
		                   " times");
	}
	//这里不需要修改,因为flock也是Quackable
	void simulate(Quackable duck) {
		duck.quack();
	}
}

 

14.既然我们有办法管理整群鸭子,我们也应该有办法来追踪个别的鸭子及其实时呱呱叫行为,我想到起了有个模式可以观察对象的行为:观察者模式
首先我们需要一个Observable接口,所谓Observable就是被观察的对象,Observable需要注册和通知观察者的方法.

//如何想被观察的Quackable都必须实现QuackObservable接口
public interface QuackObservable {
	//注册观察者,任何实现了Observer接口的对象都可以监听呱呱叫
	public void registerObserver(Observer observer);
	//通知观察者
	public void notifyObservers();
}
//现在我们需要确定所有的Quackable都实现此接口,所以干脆我们让Quackable扩展此接口
public interface Quackable extends QuackObservable {
	public void quack();
}

15.现在我们必须确定所有实现Quackable的具体类都能够扮演QuackObservable的角色.每一个类中都需要实现注册和通知,使用另外的做法:我们要在另一个Observalbe的类中封装注册和通知,然后将它和QuackObservable组合在一起,这样,我们只需要一份代码即可,QuackObservable所有的调用都委托给Observable辅助类

//Observable必须实现QuackObservable,因为他们具有一组相同的方法,
//QuackObservable会将这些方法的调用转给Observable的方法
public class Observable implements QuackObservable {
	ArrayList observers = new ArrayList();
	QuackObservable duck;
	//在次构造器中我们传进了QuackObservable.看看notifyObservers方法,
	//你会发现当通知发生时,观察者把次对象传进去.好让观察者知道是哪个对象在呱呱叫
	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);
		}
	}
	public Iterator getObservers() {
		return observers.iterator();
	}
}

 

16.整合Observable辅助类和Quackable类

public class MallardDuck implements Quackable {
	//每个Quackable都有一个Observable实例变量,在构造器中传入一个MallardDuck对象的引用
	Observable observable;
	public MallardDuck() {
		observable = new Observable(this);
	}
	public void quack() {
		System.out.println("Quack");
		//当呱呱叫时,需要让观察者知道
		notifyObservers();
	}
	//这是两个QuackObservable方法,注意我们只是委托给辅助类进行
	public void registerObserver(Observer observer) {
		observable.registerObserver(observer);
	}
	public void notifyObservers() {
		observable.notifyObservers();
	}
}

 

17.我们已经实现了Observable所需要的一切,现在需要一些观察者Observer

//Observer只有一个update方法,他需要传入一个正在呱呱叫的对象QuackObservable
public interface Observer {
	public void update(QuackObservable duck);
}
//我们需要实现Observer,否则无法以QuackObservable注册
public class Quackologist implements Observer {
	//打印出正在呱呱叫的Quackable对象
	public void update(QuackObservable duck) {
		System.out.println("Quackologist: " + duck + " just quacked.");
	}
}

 

18.我们准备开始观察了,让我们更新模拟器,了解这一切是如何工作的

public class DuckSimulator {
	public static void main(String[] args) {
		DuckSimulator simulator = new DuckSimulator();
		AbstractDuckFactory duckFactory = new CountingDuckFactory();
		simulator.simulate(duckFactory);
	}
	void simulate(AbstractDuckFactory duckFactory) {
		//other 创建鸭子工厂和鸭子
		//other 创建群

		//我们在这里所需要做的就是创建一个Quackologist,把它注册成为一个群的观察者
		Quackologist quackologist = new Quackologist();
		flockOfDucks.registerObserver(quackologist);
		
		simulate(flockOfDucks);

		System.out.println("\nThe ducks quacked " + 
		                   QuackCounter.getQuacks() + 
		                   " times");
	}
	void simulate(Quackable duck) {
		duck.quack();
	}
}

如果想观察整个群呢?有什么办法?考虑试写一下

 

未完待续...

评论
reverocean 2008-04-16
好文,学习中
发表评论

您还没有登录,请登录后发表评论

blank
搜索本博客
我的相册
5c2c51d9-1a15-3713-8084-e1742c808801-thumb
P1080256
共 30 张
存档
最新评论