设计模式在DB升级工具中的应用
从入华为到现在, 一直负责着DB升级工具的开发, 以及后续工具的升级,在这段过程中总结了部分的经验拿来和大家分享一下。 本贴主要内容是讲述DB升级工具中如何去使用到设计模式的, 但是在讲述之前, 先简单介绍一下DB升级工具的由来,其实现在的DB升级工具的前身也就是现在由网管组负责的OMU工具, 该工具本来主要目的也是为用户提供一个操作SoftCo可视化平台,在该工具的一个功能中就已经提供了一个升级DB的模块, 但是由于该模块只能针对特有的两个版本之间的升级,但是该模块功能已经无法满足其他SoftCo版本之间的升级, 且维护组已不在维护OMU工具,所以现在我们维护组现在开发的DB升级工具是在原有的基础上进行扩展。 DB升级的前世今生就先简单讲到这里, 回到主题, 为什么在DB升级工具采用设计模式呢,其主要原因是因为以前OMU中的DB升级功能在对其它的SoftCo版本之间的升级支持并不是非常的好,但是由于现在的SoftCo版本之间的差异个有不同, 并且DB升级还需要考虑到对以后SoftCo版本升级支持,那么维护组现在开发的DB升级工具需要具有高容错、易维护、易扩张的特点, 那么合理的采用设计模式可以帮我们解决以上问题。 正式进入正题中, 在DB升级工具中最关键的一个类DataUpdate中包含了最基本的处理升级的方法, 其基本代码如下:
public class DataUpdate {
private String oldVersion;
private String newVersion;
public void moveDate() throws IOException {
for (......) { // moveData标准升级处理方法
}
}
public void moveVersion() throws IOException { ...... } .
..... }
该类给我们提供了基本的升级功能, 能处理大多数升级情况, 但是却仍然无法解决现在SoftCo版本升级的功能, 尤其是DataUpdate的moveData(......)方法专门处理了数据库业务数据的迁移功能, 那么我们将工作的重心放在了该方法上, 在从导师施洋的需求中我们得到这样的一个结论, 我们的特殊处理方法, 应放在moveData(......)完全执行完后去处理(由于篇幅有限,关于数据库的结构一时半会无法解释清楚,暂时省略,如果有兴趣可以和我联系),一个疯狂的念头涌上心头, 干脆就用spring中的AOP得了, 但是无情事实摆在了我的面前, 郑建良同志每天为了如何为压缩JDK的jre文件夹搞得焦头烂额(至今仍未解决该问题), 我们的工具还会采用spring框架吗, spring的引入被否定;自己写一个代理类, 专门用来处理拦截moveData(......)的调用, 模仿spring的后期织入、围绕织入, 这个看起来很有技术含量......难道就没有更加简单的方法解决这个问题吗? 答案是肯定的。 我定义了一下这么几个类以及文件。 IAction // 特殊处理的顶层接口,该接口定义如下
public interface IAction {
// 特殊处理方法
public void execute(......) throws IOException;
// 添加特殊处理表
public void addOperOldTable(......);
// 添加特殊处理关联表
public void addOperNewTable(......);
}
AbstractAction // 抽象类,实现了IAction接口,未实现IAction中的execute(......)方法,该类定义如下
public abstract class AbstractAction implements IAction {
private static List oldTables; //需特殊处理表
private static Set newTables; //特殊处理关联表
private static Properties prop;
private static Map moduleConfig;
static {
prop.load("beans.properties"); // 获取特殊处理类
}
public AbstractAction () { // 通过sp.xml文件初始化moduleConfig, // 该map用来保存需要特殊处理的表的信息, // 以及该表所关联的其他表 }
public void addOperOldTable(......) { ...... }
public void addOperNewTable(......) { ...... }
public static IAction createAction(String name) {
try {
IAction action = Class.forName(name).newInstanceOf();
return action;
} catch() {
return null;
}
}
}
而所有的特殊处理类都继承与AbstractAction类,并实现execute方法,大家可能会产生疑问, 为什么特殊处理不直接实现IAction接口呢, 如果只是继承于IAction接口的话, 那么就无法达到本人希望加载sp.xml特殊处理描述文件的期望了, 这也是为什么我会在抽象类AbstractAction中的默认构造函数实现加载sp.xml描述文件, 由于每个版本的SoftCo升级特殊处理的表都不一样,那么在我定义的规则中所有的特殊处理类都必须和特殊处理的描述文件存在同一包下, 其目的也就是为了让父类去完成加载配置文件, 而让所有的程序员, 在实现特殊处理上只需要关心具体的业务就可以了, 也就是说, 只要继承了AbstractAction类, 那么你就只要实现execute方法就可以了。 但是为什么要还要提供一个静态方法createAction呢,等我讲道织入的那一段,大家就会明白了。 前面我们讲到,特殊处理需放在moveData方法执行后去执行, 那么在前面的内容中,一直就未提到如何解决,好了本文的重点也就在这个moveData方法上, 其代码如下:
public class DataUpdate {
private String oldVersion;
private String newVersion;
public void moveDate() throws IOException {
IAction action = AbstractAction.createAction(oldVersion + newVersion);
for (......) {
if (null != action && 是需要特殊处理的表 ) {
action.addOldTable(...);
}
if (null != action && 是特殊处理关联表 ) {
action.addNewTable(...);
} // moveData标准升级处理方法
}
if (null != action) {
action.execute();
}
}
public void moveVersion() throws IOException { ...... }
...... }
从修改的DataUpdate的moveData方法中我们可以发现,我们通过酒数据库的版本号和新数据库的版本号拼接起来的字符串作为参数调用AbstractAction.createAction(......)获取了一个特殊处理类,该类专门处理这两个版本的升级,这个时候, 抽象类AbstractAction的作用就体现了, 其实该抽象类还充当着抽象工厂的作用, 因为我的所有特殊处理类的描述信息都记录在beans.properties文件中,该文件的基本定义如下: XXXX旧版本号XXXXX新版本号=com.huawei.xxx.actions.ActionImpl 如果两个版本无需做特殊处理, 那么在beans.properties文件中就没有定义, 那么通过AbstractAction.createAction获得的特殊处理实例肯定不存在, 我们通过判断该实例是否为null值来判断该两个版本是否需要通过特殊处理, 而在moveData() 最后调用action.execute()方法, 也就达到了spring后期织入的功能, 在该设计中, 我们只是简简单单的采用了抽象工厂、模板模式就达到了实现功能的要求, 在后来的实践中, 我们所需要提供的特殊处理也就只仅仅局限于添加类,实现execute方法,了解业务上了, 大大的达到了解耦的效果。 截止发帖前,除了中文路径问题以外(该问题已解决),该设计没有出现问题, 足以证明,该设计基本成功。 本来想上传一些模式设计的文档, 可惜由于该论坛的限制, 导致无法与大家分享,十分可惜。