鸭子模拟器
学习了多种设计模式后,现在将这些设计模式用于重建鸭子模拟器
未加入设计模式
// 如果某个物体会发出叫声,就实现该接口 public interface Quackable{ public void quack(); } // 鸭鸣器(模仿鸭子叫声) public class DuckCall implements Quackable{ public void quack(){ System.out.println("Kwak"); } } // 测试鸭子模拟器 public class DuckSimulator{ public static void main(String[] args){ DuckSimulator simulator = new DuckSimulator(); simulator.simulate(); } public void simulate(){ Quackable duckCall = new DuckCall(); simulate(duckCall); } public void simulate(Quackable duck){ duck.quack(); } }
加入适配器模式
因为鸭子和鹅生活在一起,此时想要在模拟器中也能使用到鹅,可以使用适配器将鹅适配成鸭子:
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(); } public void simulate(){ Quackable gooseDuck = new GooseAdapter(new Goose()); simulate(gooseDuck); } public void simulate(Quackable duck){ duck.quack(); } }
加入装饰者模式
此时想要在不修改鸭子类的前提下给鸭子加上统计叫声次数的行为,可以使用装饰者模式:
// QuackCounter是装饰者 public class QuackCounter implements Quackable{ // 一样要实现目标接口 Quackable duck; // 因为这里想要收集所有实现了Quackable接口对象的叫声数,所以定义为静态变量 static int numOfQuck; public QuackCounter(Quackable duck){ // 传入需要装饰的对象 this.duck = duck; } public void quack(){ duck.quack(); numOfQuck++; } public static int getQuacks(){ return numOfQuck; } } // 测试鸭子模拟器 public class DuckSimulator{ public static void main(String[] args){ DuckSimulator simulator = new DuckSimulator(); simulator.simulate(); } public void simulate(){ Quackable duckCall = new QuackCounter(new DuckCall()); simulate(duckCall); System.out.println(QuackCounter.getQuacks()); // 打印所有叫声数 } public void simulate(Quackable duck){ duck.quack(); } }
加入工厂模式
为了保证每个鸭子都是被装饰过的,为什么不使用流水线工作?这不就可以使用工厂模式(为了生产各种不同类型的鸭子,使用抽象工厂模式):
public abstract class AbstractDuckFactory{ public abstract class Quakable createDuckCall(); public abstract class Quakable createMallardDuck(); } // 该工程生产装饰过的鸭子 public class CountingDuckDuckFactoy extends AbstractDuckFactory{ public Quakable createDuckCall(){ return new QuackCounter(new DuckCall()); } public Quakable createMallardDuck(){ return new QuackCounter(new MallardDuck()); } } // 测试鸭子模拟器 public class DuckSimulator{ public static void main(String[] args){ DuckSimulator simulator = new DuckSimulator(); // 1.创建一个工厂 AbstractDuckFactory duckFactory = new CountingDuckDuckFactoy(); // 2.将工厂传入模拟器(模拟器只需要知道这个工厂是生产什么的,不需要知道它怎么生产) simulator.simulate(duckFactory); } public void simulate(AbstractDuckFactory duckFactory){ // 使用工厂去创建 Quackable duckCall = duckFactory.createDuckCall(); Quackable mallardDuck = duckFactory.createMallardDuck(); simulate(duckCall); simulate(mallardDuck); System.out.println(QuackCounter.getQuacks()); // 打印所有叫声数 } public void simulate(Quackable duck){ duck.quack(); } }
加入组合模式和迭代器模式
鸭子创建很多后就不好管理,如何实现下令就能让所有鸭子都发出叫声?可以使用组合模式将所有鸭子视为集合,并且使用迭代器模式遍历所有鸭子让其发出叫声:
// 组合需要和叶子节点实现相同的接口 public class Flock implements Quackable{ ArrayList quackers = new ArrayList(); public void add(Quackable quacker){ quackers.add(quacker); } public void quack(){ // 使用ArrayList中返回的迭代器 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 CountingDuckDuckFactoy(); simulator.simulate(duckFactory); } public void simulate(AbstractDuckFactory duckFactory){ Quackable duckCall = duckFactory.createDuckCall(); // Flock是一棵树,可以管理单个鸭子,也可以管理一个鸭群 Flock flockOfDucks = new Flock(); // 1.加入单个鸭子(叶子节点) flockOfDucks.add(duckCall); // 2.加入一个绿头鸭群 Flock flockOfMallard = new Flock(); // 先创建一个绿头鸭子的子树 Quackable mallardDuck1 = duckFactory.createMallardDuck(); Quackable mallardDuck2 = duckFactory.createMallardDuck(); flockOfMallard.add(mallardDuck1); flockOfMallard.add(mallardDuck2); flockOfDucks.add(flockOfMallard); // 将该子树加入到总树中 simulate(flockOfDucks); simulate(flockOfMallard); System.out.println(QuackCounter.getQuacks()); // 打印所有叫声数 } public void simulate(Quackable duck){ duck.quack(); } }
加入观察者模式
如果想追踪个别鸭子,那就可以使用观察者模式:
// 任何想被观察的Quackable都要实现该接口 public interface QuackObservable{ // 任何实现了Observer接口的对象都可以监听叫声 public void registerObserver(Observer observer); public void notifyObservers(); // 通知观察者 } public interface Quackable extends QuackObservable{ // 接口可以继承的 public void quack(); } // 辅助类 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 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); } public void notifyObservers(){ observable.notifyObservers(); } }
// 观察者需要实现该接口 public interface Observer{ public void update(QuackObservable duck); } // 专门观察鸭子叫声的学者 public class Quackologist implements Observer{ public void update(QuackObservable duck){ // 打印出正在叫的鸭子 } }
// 测试鸭子模拟器 public class DuckSimulator{ public static void main(String[] args){ DuckSimulator simulator = new DuckSimulator(); AbstractDuckFactory duckFactory = new CountingDuckDuckFactoy(); simulator.simulate(duckFactory); } public void simulate(AbstractDuckFactory duckFactory){ // 其余代码和上一节中一致 Quackologist quackologist = new Quackologist(); // 因为Flock实现了Quackable接口,而Quackable接口继承了QuackObservable接口,所以可以调用registerObserver方法 flockOfDucks.registerObserver(quackologist); } public void simulate(Quackable duck){ duck.quack(); } }
复合模式
- 结合两个或以上的模式,组合一个解决方案,用于解决一再发生的一般性问题