1.详细功能
- 能够控制整个X-gen的调用过程,并能够灵活地扩展这个调用过程
- 调用theme提供的Action来具体实现每一个需要生成的功能
- 能够在每个Action执行前后,动态组合添加一些功能
- 能很灵活地通知多个输出实现,并能实现调用模块和输出模块的解耦
2.功能边界
- 只负责具体的generate调用过程
- 不关心generate的数据从何而来
- 不关心实际如何generate
- 不关心按照什么流程顺序来generate
- 不关心每个步骤都需要完成些什么功能,那都不是固定的,完全可以通过配置或者是开发人员在外部theme中来定
3.对外的接口
4.内部实现
实现的起点
为了让大家更好的理解调用模块的内部实现架构,因此先以一个最简单的实现结构为起点,采用重构的方式,逐步把相关的设计模式应用进来,从简单到复杂,从而让大家更好的看到如何选择要使用的设计模式、如何实际应用设计模式以及如何让多种设计模式协同工作。
1.针对前面定义的API,提供一个最基本的实现。其实,真正调用的实现就相当于命令模式的receiver
4.1 状态模式
4.1.1 面临的问题
来思考上面的实现,现在在executeGen方法里面只有两步实现,可是不排除今后有更多需要调用的功能,比如:在内容生成后执行事件处理等等。
通常情况下,我们还希望保持DefaultGenInvocation的通用性,该怎么办呢?换句话说,executeGen方法里面的调用流程是可能变动的,或者是需要添加新的流程步骤,或者是需要改变调用的顺序等等。
该怎么实现这样的功能呢?
4.1.2 用状态模式来解决
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
4.1.3 使用状态模式来解决问题的思路
要解决上面的问题,一个很简单的思路就是:其实就是相当于用状态模式来模拟调用的工作流程,把调用流程的每一步单独包装成为一个状态对象,然后在一个对象执行过后,由这个状态对象来设置下一步状态,使得流程继续流转。
4.1.4 此时具体调用模块的结构示意如图
4.2 模板方法
4.2.1 面临的问题
面临的问题在调用每个theme的action来generate内容的时候,虽然action是由theme提供的,也就是由开发人员自行扩展的,但是调用action的过程是一样的。
有些朋友会想,调用过程一样的,那就做成公共的功能吧,但是又发现其中某些步骤执行的功能并不一样,比如具体的action的处理是不一样的,这该如何处理呢?
4.2.2 用模板方法模式来解决
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
4.2.3 使用模板方法模式来解决问题的思路
既要约束子类的功能,又要为子类提供公共的功能,很明显应用抽象类来做一个公共的父类。而公共功能中某些步骤执行的功能并不一样,那就可以把这些不一样的功能延迟到子类来执行,在父类中只要定义相应的抽象方法就好了。
从而把调用过程看成是算法的骨架,而调用action的处理方法,当作原语操作,只有子类才知道如何实现具体的generate;而在action操作前后调用的方法,并不是每个generate都需要的功能,因此可以当作钩子方法来实现,也就是在父类中给出默认的实现,而子类根据需要来覆盖。
4.2.4 此时具体调用模块的结构示意如图
4.3 工厂方法
4.3.1 面临的问题
面临的问题观察上面的实现,发现在模板方法generate里面,调用的第一步,需要得到用来封装generate内容的对象。
但是在父类里面,它并不知道究竟要generate成为什么样子,只有theme中的action才知道具体是什么类型,也就是说父类不知道某个对象的类型,也不知道如何获取这个对象,该怎么办呢?
4.3.2 用工厂方法模式来解决
定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到其子类。
4.3.3 使用工厂方法模式来解决问题的思路
要解决上面的问题,一个很简单的思路就是:在父类里面定义一个抽象方
法,返回模板方法需要的对象,把初始化对象的任务延迟到子类去。
这个方法就是一个工厂方法,同时也作为模板方法模式里的原语操作之一。
4.3.4 此时具体调用模块的结构示意如图
4.4 装饰器
4.4.1 面临的问题
面临的问题分析上面的实现,在调用模板方法generate的过程中,可能需要在具体的 Action之前执行一定的功能,也可能需要在具体的Action之后执行一定的功能,而且这些功能具体是什么,具体的Action方法并不知道。
也就是说,需要在Action方法不知情的情况下,给他添加上新的功能,可能会在action方法之前或者之后执行一些功能。该怎么办呢?
4.4.2 用装饰者模式来解决
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活。
4.4.3 使用装饰者模式来解决问题的思路
要解决上面的问题,一个很简单的思路就是:定义一个公共的组件对象,作为原始对象和装饰对象的父类,然后在装饰对象里面,采用动态组合的方式来给传入的组件对象透明的添加新的功能
4.4.4 此时具体调用模块的结构示意如图
4.5 观察者模式
4.5.1 面临的问题
继续分析上面的实现,在加入了模板方法模式、工厂方法模式和装饰器模式过后,在DefaultGenInvocation的executeGen方法里面,调用每个theme的 action来生成内容的功能就很容易实现出来了。
可是,把内容输出去的步骤应该怎么实现呢?
按照现在的要求,同一个generate的功能,可能会有多个输出,输出形式还不一样,那么,该怎么实现这个功能呢?
4.5.2 用观察者模式来解决
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
4.5.3 使用观察者模式来解决问题的思路
要解决上面的问题,一个很简单的思路就是:把生成调用当成目标对象,而需要输出的对象当成多个观察者,这样一来,当目标对象的状态变化的时候,也就是需要输出的内容已经generate过后,就可以通知这多个观察者,让这些观察者自行输出内容。
4.5.4 此时具体调用模块的结构示意如图
5.和其他模块的交互实现
使用中介者模式
参考
- 1)《设计模式综合项目实战》——跟着cc学设计系列