1.在这一章中,我们要通过一个例子把前边学习过的设计模式串一遍,以一种需求不断叠加的实际工作场景为背景。首先我们还是把我们第一个模式所举的鸭子的例子搬出来,我们要创建一个模拟器对这些鸭子的叫声进行模拟:
首先我们设计一个呱呱叫的接口:
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();
}
}
2.一会儿,你发现问题来了:要是在这个模拟器中加入鹅叫声的模拟该怎么办呢,毕竟鹅是下边这样定义的:
public class Goose {
public void honk() {
System.out.println("Honk");
}
public String toString() {
return "Goose";
}
}
其实,我们想到可以用适配器模式将这个方法转换一下:
public class GooseAdapter implements Quackable {
Goose goose;
public GooseAdapter(Goose goose) {
this.goose = goose;
}
public void quack() {
goose.honk();
}
public String toString() {
return "Goose pretending to be a Duck";
}
}
下边我们要做就是在模拟器中创建Goose对象,并把它放到适配器中:
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());//使用了适配器,我们屏蔽了二者的差异,并且通过面向接口编程让主程序中也不必再做大的修改。
System.out.println("/nDuck Simulator: With Goose Adapter");
simulate(mallardDuck);
simulate(redheadDuck);
simulate(duckCall);
simulate(rubberDuck);
simulate(gooseDuck);
}
void simulate(Quackable duck) {
duck.quack();
}
}
3.新的需求又来了:我们要统计有多少种鸭子(不含鹅)叫声。
此时我们使用的是装饰者模式——将鸭子包装为装饰者对象,给鸭子一些新的行为:
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 String toString() {
return duck.toString();
}
}
我们根据这个模式重构我们的模拟器:
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();
}
}
4.我们现在要讲创建和装饰放在一起,以保证鸭子一定被装饰模式进行修饰——为了能生产不同的鸭子,我们要用抽象工厂模式:
public abstract class AbstractDuckFactory {
public abstract Quackable createMallardDuck();
public abstract Quackable createRedheadDuck();
public abstract Quackable createDuckCall();
public abstract Quackable createRubberDuck();
}
首先我们创建一个工厂——创建有装饰者的鸭子:
public class CountingDuckFactory extends AbstractDuckFactory {
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());
}
}
基于工厂模式,我们可以如下构造模拟器:
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();
}
}
5.我们看了看代码,发觉这样一个个simulate太麻烦,能不能一个指令下去,这个模拟动作就能一下“群发”出去,因为我们现在要建立很多的鸭子,并且将它们分群,若一个个模拟太费劲了:
我们想起组合模式,在这个模式里,我们能像对待单个对象一样对待一个对象集合(在那个例子中,是含有子菜单的菜单项),我们现在创建一群鸭子的类:
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 String toString() {
return "Flock of Quackers";
}
}
这样,我们的模拟器就如下:
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 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(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); //这就形成了类似带有子菜单项的菜单,与上次不同的是,我们只在Flock中实现了add,而没有在Quackable 中定义这个add方法——菜单项和菜单的处理是不同的。这样处理的意义在于向Duck加入add方法是没有意义的,但如此一来程序的透明性(一个Quackable对象必须是Flock才能完成)就有所下降——这是一个Compromise
System.out.println("/nDuck Simulator: Whole Flock Simulation");
simulate(flockOfDucks);
System.out.println("/nDuck Simulator: Mallard Flock Simulation");
simulate(flockOfMallards);
System.out.println("/nThe ducks quacked " +
QuackCounter.getQuacks() +
" times");
}
void simulate(Quackable duck) {
duck.quack();
}
}
6.我们此时有个需求,要观察个别鸭子的行为——那么此时,我们合适用观察者模式。
首先,我们需要一个Observable接口,想要实现被观察的Quackable都要实现这个接口:
public interface QuackObservable {
public void registerObserver(Observer observer);
public void notifyObservers();
}
然后我们要求所有的鸭子或者鹅到能有被监控的能力:
public interface Quackable extends QuackObservable {
public void quack();
}
接着,我们要在所有实现了Quackable 的类中能够完全具有QuackObservable 的能力,但这时我们发现要在太多的类中加入这些代码,这恐怕并不是我们想要的,此时,我们选择在另一个叫做Observable的类中封装注册和通知的代码,这个辅助类一会儿将被我们组合进来。
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);
}
}
public Iterator getObservers() {
return observers.iterator();
}
}
这样我们就能将这个Observable 类整合到各个类中,举一个例子MallardDuck类:
public class MallardDuck implements Quackable {
Observable observable;//我们在这个类中保留了一个Observable 引用,在后边实现QuackObservable 类的方法时被包装进来,实现整合
public MallardDuck() {
observable = new Observable(this);
}
public void quack() {//实现了Quackable 接口
System.out.println("Quack");
notifyObservers();//在“呱呱”叫的时候通知观察者
}
public void registerObserver(Observer observer) {//这个方法只是QuackObservable 类的方法,因为Quackable extends QuackObservable 。
observable.registerObserver(observer);
}
public void notifyObservers() {//这个方法只是QuackObservable 类的方法,因为Quackable extends QuackObservable 。
observable.notifyObservers();
}
public String toString() {
return "Mallard Duck";
}
}
在完成被观察者后,我们完成
public interface Observer {
public void update(QuackObservable duck);//传入正在呱呱叫的对象
}
我们创建一个类来对呱呱叫这个事件进行反应,在这个时间发生时,update方法会被调用,此时我们打印出是哪一个对象在叫:
public class Quackologist implements Observer {
public void update(QuackObservable duck) {
System.out.println("Quackologist: " + duck + " just quacked.");
}
public String toString() {
return "Quackologist";
}
}
好的,大功告成,我们可以构建我们的模拟器了:
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 redheadDuck = duckFactory.createRedheadDuck();
Quackable duckCall = duckFactory.createDuckCall();
Quackable rubberDuck = duckFactory.createRubberDuck();
Quackable gooseDuck = new GooseAdapter(new Goose());
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);
System.out.println("/nDuck Simulator: With Observer");
Quackologist quackologist = new Quackologist();
flockOfDucks.registerObserver(quackologist);
simulate(flockOfDucks);
System.out.println("/nThe ducks quacked " +
QuackCounter.getQuacks() +
" times");
}
void simulate(Quackable duck) {
duck.quack();
}
}