iBATIS&Spring合奏(四)--设计模式in iBATIS
现在总结一下iBATIS框架中用到的优美的设计模式。并不是强调设计模式有多强大或者iBATIS有多牛叉,只是在看源码的过程中的一些丝丝缕缕,觉得有很多值得学习的地方。按照不同层次的实现一点点分析和整理。以下的类图和序列图有画的不到位的地方请见谅,因为实在不很在行,用EA画图很痛苦……
一、SQL Map配置解析
关于配置文件的解析,iBATIS运用了DOM解析加动态代理的方式实现。其中运用了大量经典的设计模式。为了简单说明源码中应用设计模式的核心API。将于下文以看图说话的方式展现关于设计模式在iBATIS框架中的应用探讨。
1、基于策略模式(Strategy)解析SqlMapConfig——Nodelete,一个XML节点接口。
先简单说明下策略模式(Strategy)。Gof提供的解释是针对一组算法,进行封装到有共同接口的独立类中,这样就可以像选择不同的策略一样替换算法。按照字面还是很好理解的。下面画张图(万恶的图啊……EA画图的原文件也会共享给大家,需要EA软件)
显然,Nodelete接口就是传说中的Strategy,Nodelete是Context角色。SqlMapConfigParser类中创建的匿名类是ConcreteStrategy角色。SqlMapConfigParser在实例化构造函数中调用具体的addXX方法,这些方法内部匿名类实现了process方法。根据XML配置文件不同的节点,采用不同的处理节点方式,而具体的实现就在这些方法中的内部类对象。而解析是遍历节点方式,主要实现是在NodeleteParser中。大家可以参看该类中的源码,运用了DOM方式解析。通过策略模式使不同节点处理方式灵活调用,相互替换。
2、基于调停者模式(Mediator)实现的对象解析——XmlParserState。
Mediator也叫协调者,中介者。一个比较通俗的解释是:Mediator设计有与组件沟通的介面,介面中封装了与其它组件互动细节,组件与组件之间不用知道彼此的存在,它们只要与Mediator沟通就好了,利用这种方式,可以切开组件与组件之间的耦合。那在iBATIS框架解析节点时,这个中间者就是要达到一个通用的效果,因为节点之间有包含关系,但是解析方式是不同的。而作为协调方——XmlParserState出现了。先看看图图:
做些解释。SqlMapConfigParser实例化对象是主解析类。先看一下人家的构造函数吧:
public class SqlMapConfigParser { protected final NodeletParser parser = new NodeletParser(); private XmlParserState state = new XmlParserState(); private boolean usingStreams = false; public SqlMapConfigParser() { parser.setValidation(true); parser.setEntityResolver(new SqlMapClasspathEntityResolver()); addSqlMapConfigNodelets(); addGlobalPropNodelets(); addSettingsNodelets(); addTypeAliasNodelets(); addTypeHandlerNodelets(); addTransactionManagerNodelets(); addSqlMapNodelets(); addResultObjectFactoryNodelets(); }
private void addTypeAliasNodelets() { parser.addNodelet("/sqlMapConfig/typeAlias", new Nodelet() { public void process(Node node) throws Exception { Properties prop = NodeletUtils.parseAttributes(node, state.getGlobalProps()); String alias = prop.getProperty("alias"); String type = prop.getProperty("type"); state.getConfig().getTypeHandlerFactory().putTypeAlias(alias, type); } }); }
public SqlMapExecutorDelegate() { mappedStatements = new HashMap(); cacheModels = new HashMap(); resultMaps = new HashMap(); parameterMaps = new HashMap(); sqlExecutor = new SqlExecutor(); typeHandlerFactory = new TypeHandlerFactory(); dataExchangeFactory = new DataExchangeFactory(typeHandlerFactory); }