关于复合模式、策略模式,工厂模式、观察者模式、装饰模式的一个好例子
来源:互联网 发布:龙门镖局源码 编辑:程序博客网 时间:2024/06/03 02:13
原帖地址:http://chat.javaeye.com/blog/178414
我们将再次使用鸭子的例子来说明并学习,下一章我们会拜访一个真正的复合模式--MVC,没错,就是MVC.
1.首先,我们将创建一个Quackable接口
- public interface Quackable {
- //只做一件事:呱呱叫
- public void quack();
- }
2.现在,某些鸭子实现了Quackable接口
- 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");
- }
- }
3.好了,我们有了鸭子,还需要一个模拟器,制造一个会产生鸭子,还要确认鸭子呱呱叫的模拟器
- public class DuckSimulator {
- public static void main(String[] args) {
- //创建一个模拟器,调用simulate方法
- DuckSimulator simulator = new DuckSimulator();
- simulator.simulate();
- }
- void simulate() {
- //每一种会呱呱叫的鸭子都有一份实例
- Quackable mallardDuck = new MallardDuck();
- Quackable redheadDuck = new RedheadDuck();
- Quackable duckCall = new DuckCall();
- Quackable rubberDuck = new RubberDuck();
- //模拟每种鸭子
- simulate(mallardDuck);
- simulate(redheadDuck);
- simulate(duckCall);
- simulate(rubberDuck);
- }
- void simulate(Quackable duck) {
- //重载了simulate方法来模拟一种鸭子,剩下的事让多态发挥它的魔法
- duck.quack();
- }
- }
4.只要有水塘的地方,就大概会有鸭子和鹅,我们为这个模拟器设计一个鹅类
- public class Goose {
- //鹅的叫声是咯咯
- public void honk() {
- System.out.println("Honk");
- }
- }
5.我们需要鹅适配器,既然鹅不会呱呱叫,那么我们可以利用适配器将鹅适配成鸭子
- public class GooseAdapter implements Quackable {
- Goose goose;
- //传入要适配的对象
- public GooseAdapter(Goose goose) {
- this.goose = goose;
- }
- //当调用quack时,会被委托到鹅的honk方法
- public void quack() {
- goose.honk();
- }
- }
6.现在,模拟器中也应该可以使用鹅了,我们需要做的就是创建goose对象,将它包装进适配器
- public class DuckSimulator {
- public static void main(String[] args) {
- //创建一个模拟器,调用simulate方法
- DuckSimulator simulator = new DuckSimulator();
- simulator.simulate();
- }
- void simulate() {
- //每一种会呱呱叫的鸭子都有一份实例
- Quackable mallardDuck = new MallardDuck();
- Quackable redheadDuck = new RedheadDuck();
- Quackable duckCall = new DuckCall();
- Quackable rubberDuck = new RubberDuck();
- //通过把goose包装进gooseAdapter,我们就可以让鹅像鸭子一样
- Quackable gooseDuck = new GooseAdapter(new Goose());
- //模拟每种鸭子
- simulate(mallardDuck);
- simulate(redheadDuck);
- simulate(duckCall);
- simulate(rubberDuck);
- //一旦鹅被包装进来,我们就可以把它当做其他鸭子的Quackable对象
- simulate(gooseDuck);
- }
- void simulate(Quackable duck) {
- //重载了simulate方法来模拟一种鸭子,剩下的事让多态发挥它的魔法
- duck.quack();
- }
- }
7.测试一下上面的DuckSimulator,你会发现,鹅和其他鸭子一起叫.现在我们考虑一下,我们如何在不变化鸭子类的情况下,计算呱呱叫的次数呢?有什么模式可以解决这个问题?
8.让我们创建一个装饰者,通过把鸭子包装进装饰者对象,给鸭子一些新行为(计算次数),我们不必修改鸭子的代码
- //QuackCounter是一个装饰者,像适配器一样实现Quackable
- public class QuackCounter implements Quackable {
- //我们用一个实例变量来记录被装饰的呱呱叫对象
- Quackable duck;
- //用静态变量跟踪所有呱呱叫次数
- static int numberOfQuacks;
- public QuackCounter(Quackable duck) {
- this.duck = duck;
- }
- //当quack被调用时,我们就把调用委托给正在装饰的Quackable对象,然后把叫声的次数加一
- public void quack() {
- duck.quack();
- numberOfQuacks++;
- }
- //给装饰者加入一个静态方法,以便返回在所有Quackable中发生的叫声次数
- public static int getQuacks() {
- return numberOfQuacks;
- }
- }
9.现在我们必须包装在QuackCounter装饰折中被实例化的每个Quackable对象,如果不这么做,鸭子会到处乱跑而使得我们无法统计叫声次数,我们需要更新模拟器,以便创建被装饰的鸭子
- public class DuckSimulator {
- public static void main(String[] args) {
- DuckSimulator simulator = new DuckSimulator();
- simulator.simulate();
- }
- void simulate() {
- //每次我们创建一个Quackable,就用一个新的装饰者包装它
- Quackable mallardDuck = new QuackCounter(new MallardDuck());
- Quackable redheadDuck = new QuackCounter(new RedheadDuck());
- Quackable duckCall = new QuackCounter(new DuckDuck());
- Quackable rubberDuck = new QuackCounter(new RubberDuck());
- //鹅不是呱呱叫,所以不用包装
- Quackable gooseDuck = new DooseAdapter(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();
- }
- }
我们为什么不将创建鸭子的程序集中在一个地方呢?换句话说,让我们将创建和装饰的部分包装起来,这看起来像是什么模式?
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();
- }
- }
- 关于复合模式、策略模式,工厂模式、观察者模式、装饰模式的一个好例子
- 设计模式---复合模式(策略-适配器-装饰者-抽象工厂-组合-观察者)
- 策略模式+观察者模式+装饰者模式
- 简单工厂模式/策略模式/装饰模式
- 设计模式(一) 观察者模式、装饰模式、工厂模式
- 关于装饰模式的一个小例子
- 策略模式、观察者模式
- 设计模式——单例模式、工厂模式、代理模式、观察者模式、装饰器模式
- 观察者模式 和 工厂模式
- PHP设计模式 五 (观察者 策略 装饰器模式)
- 关于过滤器的一个例子(涉及到装饰模式)
- 学习观察者模式的一个例子
- 一个简单的观察者模式例子
- head first design patterns(1):策略模式,观察者模式,工厂模式,抽象工厂模式
- 单列模式,工厂模式,观察者模式
- 单利模式工厂模式和观察者模式
- 装饰模式+工厂模式+模板模式
- 设计模式---策略模式And 观察者模式
- 彩虹社区公测了
- IA-64 Linux存储管理
- WF学习资料汇总
- 对.NET三层结构的理解
- 关于transient修饰符
- 关于复合模式、策略模式,工厂模式、观察者模式、装饰模式的一个好例子
- JS金额小写转大写
- windows窗口消息
- 关于Silverlgiht Tools的离线安装
- 鄙视的笔试
- C++/CLI实战
- VB.NET 全角转半角
- 怎样成为一个黑客??如何计划??/
- httpd: bad user name apache