ExtFrame里的核心设计模式之二
本章介绍框架里的IOC机制及另一个核心设计模式:TemplateMethod
TemplateMethod模式就是所谓的模版了,刚开始跟别人介绍说用这个模式时,很多人说你做的是CMS么,我去看了下CMS的介绍,应该是两回事吧
我这里使用这个模式不是提供模版给网站,而是提供处理业务逻辑的模版给开发人员
简单的说,就是系统的大多数逻辑,我都做了个模版给你,你能用就用,不能用的话久继承扩展,只修改需要改的地方
所谓的TemplateMethod模式,本身就是OOP的继承与重载的一个实现
从架构来说,就是有一类功能(例如数据的保存),定义成一个接口,然后为这个接口实现一个通用类,这样,系统的大多数这类的逻辑就可以使用这个通用类来完成了,而如果通用类满足不了要求时怎么办?比较极端的情况,是重写一个接口类,但是一般的情况下,我们可以使用一个子类来继承这个通用类,并override掉里面不满足要求的部分来实现特殊的要求,在遇到这个特殊的业务逻辑时,就不载入通用类,而是使用子类来替代处理,这就是TemplateMethod模式的机制了
而选择哪个接口的实现类来处理业务逻辑,就是系统的IOC机制了
之所以把这个设计模式列为核心之一,原因就是从很久以前的项目开始我们就一直在做的:寻求能够解决系统绝大多数问题的通用解决方案
对一个OA系统,开发遇到的最常见的功能是什么?大概就是一些表单数据的CRUD了(当然,其实所有系统都要处理CRUD问题),其实开发人员很多的时间,是花费在了不同的表单数据的CRUD功能上
在Java的EJB及SSH框架里,每一种数据类型需要创建一个类(Model),每个Model需要为它创建一个DAO,每个DAO还需要编写一个Action去调用,虽然Hibernate已经将Model的持久化工作给自动实现了,但是仍然需要编写很多重复的代码,而且当数据库发生变更时,Model类需要修改代码,重新编译
而我们从一开始设计持久层时(这个有很长时间了),就是出于这么几点考虑:
1、数据库变更时不需要修改代码及重新编译,甚至可以让用户自己处理
2、通过通用机制去实现CRUD这样的功能,数据的CRUD无需额外编码
不得不说,过去的框架在第2点上做的比较糟糕,通过ashx的类去实现了这样的功能,在HttpModule层加载了一个实体处理程序来对CRUD进行通用处理,通过扩展ashx并根据传递的命令重载对应的处理方法来实现特殊逻辑,弄的代码异常的难读,再加上前台的脚本经常搞的我不知道在做什么,遇到BUG那是一个头疼
而在设计这个框架时,就确定了第2点抛弃了原本的机制,而对1则保留了旧版本代码的持久层及模型层,只修正了一些BUG及抛弃了一些不必要的东西
对CRUD及其他功能,就完全采取了TemplateMethod模式与IOC机制结合的方式
关于IOC机制,先举前面一章关于另一个核心机制Command的例子吧
前台的按钮是通过CommonButtonBuilder类来构造的,运行时,这个类会通过Ajax传递名称给CommandController,由CommandController返回一组按钮的数据给它构造按钮
CommandController根据名称,从系统配置类里获取到这个名族对应的一组操作的配置定义,如果这组操作没有定义过滤器,那么就直接返回了,在有过滤器定义的情况下,就会从系统的IOCContainer里获取对应的过滤器,并且执行过滤器接口的过滤方法
系统默认提供了多个过滤器,例如通过权限进行过滤,工作流有专用的工作流过滤器
在遇到业务逻辑问题时,例如,文档表格里,对每个文档能签出时应当显示签出按钮,能签入时应当显示签入按钮,这时系统默认的过滤器不能满足要求,那么只需要重新写一个实现接口的过滤器,并且配置成IOC对象就可以了
如果遇到又要通过权限,又有业务逻辑的控制时怎么办?
我一开始是设计成TemplateMethod模式,让开发人员继承权限过滤器,然后在执行完后再补个业务逻辑上去,后来想想笑了,修改了下执行过滤器的代码,变的很简单,把过滤器串起来用逗号隔开就好了,让每个过滤器都过滤一遍
下面介绍CRUD的实现
CRUD通过 DataController对应的CRUD方法来实现功能,也就是前台脚本无论处理的数据是什么,只需要发送到/Data/Add(或Update、Delete等)这样的地址就可以了,无需为每种数据建立地址
在对应的方法里,首先从参数里获取到当前要处理的数据类型,然后根据配置文件获取这个类型的数据是否有如下两个IOC对象:
1、SecurityHandler
2、DataHandler
SecurityHandler用来进行系统的安全校验:当前用户是否有这么做的权限,防止用户发送非法的POST数据,如果没有定义,说明该数据无需验证,使用Ajax操作的系统,要提防有不良用户干非法的事情
而DataHandler就是当前数据的CRUD处理的对象,如果没有定义,使用默认的对象去处理
举个实际的例子:用户信息,当用户信息被删除时,需要删除一些相关信息,这时通用的操作便不能满足要求了,这时我的做法就是重写了一个UserDataHandler继承了CommonDataHandler这个母模版类,然后重载了DeleteData的方法,这样,添加修改查询什么的逻辑都没变
在DeleteData方法里,删除掉用户信息,然后再删除其他信息?啊哦,这样写太死了,如果涉及到的模块多很麻烦的,应该这样写:
删除掉用户信息后,在系统里引发一个用户删除的事件,然后呢,想处理的模块自己响应吧
例如,系统权限模块响应了,这个模块做的事是删除掉该用户和角色的所有关联
TemplateMethod模式在框架里的功能就介绍完了
框架里有哪些地方应用了这个模式呢?
除了CRUD外,还有:表格数据的生成(见表格一章),树的构造及数据的获取等,貌似系统也就这么多通用逻辑,其实框架本身也不复杂,总共在使用的核心Controller也就十来个
这种模式的优点我想读完的人也都懂了,系统容易维护,容易扩展