设计模式在项目中的应用

 

设计模式在实际项目中的应用
 
概要
Leader 设计并实现了一个基于OSGI的架构,不同的功能模块以插件的形式溶入这个系统。
由于使用了ibatis,所以不同模块注入后就产生了一个需求。需要提供一个管理器,管理ibatis的配置文件,实现动态的加载卸载不同模块。这个任务交给了我。
 
需求分析
Hibernate支持配置文件的融合。但是ibatis我没有找到相应的解决方案。
 
这个管理器需要实现配置文件的融合、分离、动态的生成SqlMapClient以及DaoManager还要在相应的操作结束后打印日志,甚至需要给使用这个管理器的用户提供很高的灵活性和可扩展性。用户可能只注册(注销)模块,但是不马上更新SqlMapClient以及DaoManager,所以需要管理器缓存某些操作以及一些信息。
 
设计与实现
 
当一个新的模块注入以后,需要通知管理器,管理器会根据条件判断是否去重新加载新的配置文件并替换目前的SqlMapClient以及DaoManager的实例。注册后,注销前,重新生成实例这3个阶段,需要处理不同的事件。
 
这个过程可以效仿swing中,在按钮上的事件监听。为管理器添加监听器,不同的监听器完成不同的功能。所完成的功能由使用者定制。管理器只是去执行特定的监听器上的方法。这样可以给客户提供很大的灵活性。
 
观察者模式(the Observer pattern)进入我们的视野。
 
这个模式的一个关键是:管理器不需要知道是谁触发了事件,如何去处理这些事件,它的职责就是完成xml的注册、注销、更新2个对象。管理器会在不同方法被调用时,迭代已经注册的tracker,触发tracker的不同事件。如果想给管理器添加不同的事件(如增加日志输出、校验、whatever),用户只需要在触发管理器不同的事件后,为管理器添加不同的功能的tracker即可。而不需要去更改被观察的对象(管理器)。增加跟踪器无需更改被观察者。
 
这个过程很像在面板上添加多个按钮,每个按钮完成什么操作面板并不知道,当触发了按钮,按钮会完成一个由客户定义的操作。不同的操作,不会引起面板的逻辑的改变。变的只不过是不同的adapter。
 
使用了the Observer pattern 难道就可以解决所有的问题吗?
 
 
答案是否定的。
问题有2个,用户在调用管理器的方法获得SqlMapClient,DaoManager的时候:
1 如何去判断这个SqlMapClient,DaoManager是否需要更新;
2 如何让SqlMapClient,DaoManager针对更新作出调整呢?
 
我们可以用另一个模式去解决以上的问题: 代理(the Proxy Pattern)
对SqlMapClient,DaoManager做代理;事件驱动SqlMapClient,DaoManager的重置。
 
代理的作用是:
 
将系统中最新的SqlMapClient,DaoManager对象的实例,替换系统中的已有的实例。并且在更新实现相应的事件或者提供不同的事件。
 
管理器可以通过透明代理的方式,让客户感觉不到SqlMapClient,DaoManager实例的变动。
 
具体的接口设计:
public interface ISqlMapBuilderManager {
……
    /**
     *注册sql map 配置信息 注册成功后该方法会触发Tracker的afterSqlMapConfigRegistered
     * 如果注册引发client或daomanager重建(由isAutoRebuild()决定),
     * 则会触发Tracker的afterSqlMapClientRebuild/afterDaoManagerRebuild
     *
     * @param id
     *            配置id
     * @param inputStream
     *            配置信息输入流
     */
    public void registerSqlMapConfig(Object id, InputStream inputStream)
            throws IbatisBuildException;
 
    /**
     * 注销sql map配置信息 注销前该方法会触发Tracker的beforeSqlMapConfigUnregistered
     * 如果注销引发client或daomanager重建(由isAutoRebuild()决定),
     * 则会触发Tracker的afterSqlMapClientRebuild/afterDaoManagerRebuild
     *
     * @param id
     */
    public void unregisterSqlMapConfig(Object id) throws IbatisBuildException;
 
    /**
     * 获得sql map client 并指定是否重新创建
     *
     * @param rebuild
     *            是否重新创建
     * @return
     */
    public SqlMapClient getSqlMapClient(boolean rebuild);
 
public void addTracker(ISqlMapTracker tracker);
……
}
 
public interface ISqlMapTracker {
       /**
        * 获得 tracker 的 id,该id用于注册
        * @return
        */
       public String getId();
      
       /**
        * 当新的配置信息被注册事触发
        * @param id 配置id
        * @param configuration 配置信息
        */
       public void afterSqlMapConfigRegistered(Object id,IConfiguration configuration);
       /**
        * 当配置信息注销前触发
        * @param id
        * @param configuration
        */
       public void beforeSqlMapConfigUnregistered(Object id,IConfiguration configuration);
       /**
        * 当SqlMapClient对象被重新构建后触发
        * @param sqlMapClient
        */
       public void afterSqlMapClientRebuild(SqlMapClient sqlMapClient);
       /**
        * 当DaoManager重新构建后触发
        * @param daoManager
        */
       public void afterDaoManagerRebuild(DaoManager daoManager);
      
}
 
透明代理的实现:
 
public class SqlMapBuilderManager implements ISqlMapBuilderManager {
……
    public SqlMapClient getSqlMapClient(boolean rebuild) {
 
        if (rebuild) {
 
            SqlMapClientProxy proxy = new SqlMapClientProxy(this.sqlMapClient);
 
            this.addTracker(proxy);
 
            return proxy;
        } else {
 
            return sqlMapClient;
        }
}
……
}
 
 
public class SqlMapClientProxy implements SqlMapClient, ISqlMapTracker {
……
       public SqlMapClientProxy(SqlMapClient sqlMapClient) {
 
              this.sqlMapClient = sqlMapClient;
       }
 
       public void beforeSqlMapConfigUnregistered(Object id,
                     IConfiguration configuration) {
 
        System.out.println("sqlManager 已经卸载成功");
       }
……
}
 
测试代码:
 
       public void test() {
              SqlMapBuilderManager builderManager = new SqlMapBuilderManager();
 
              try {
 
                     builderManager.registerSqlMapConfig("1",
                                                 new FileInputStream("sql-map-config3.xml"));
 
                     assertNull(builderManager.getSqlMapClient());
           
            SqlMapTrackerAdapters trackerAdapter = new SqlMapTrackerAdapters();
           
            builderManager.addTracker(trackerAdapter);
           
            builderManager.setAutoRebuild(true);
           
                     builderManager.registerSqlMapConfig("2",
                                                 new FileInputStream("sql-map-config4.xml"));
                    
 
            assertNotNull(builderManager.getSqlMapClient(true));
           
                     builderManager.registerSqlMapConfig("3",
                    new FileInputStream("sql-map-config5.xml"));
                    
            
                     builderManager.unregisterSqlMapConfig("2");
 
                     assertNotNull(builderManager.getSqlMapClient(true));
 
              } catch (Exception e) {
                     e.printStackTrace();
              }
       }
 
配合上面提到的实现以及这个测试,我们可以了解builderManager的工作过程:
 
我们可以为管理器设置不同的监听器,以增加不同的功能。但是扩展对于管理器本身来说是透明的。代理让SqlMapClient的更新变得透明,而且提供了Tracker特定事件的实现。
 
实现的过程中,很容易写出来如下的代码:
 
    private void runTrackerAfter(Object id, IConfiguration result) {
 
        for (Iterator it = trackerList.keySet().iterator(); it.hasNext();) {
            String tId = (String) it.next();
            ISqlMapTracker tracker = (ISqlMapTracker) this.trackerList.get(tId);
            tracker.afterSqlMapConfigRegistered(id, result);
        }
    }
 
 
    private void runTrackerBefore(Object id, IConfiguration unUse) {
 
        for (Iterator it = trackerList.keySet().iterator(); it.hasNext();) {
 
            ISqlMapTracker tracker = (ISqlMapTracker) it.next();
            tracker.beforeSqlMapConfigUnregistered(id, unUse);
        }
    }
 
 
    private void runTrackerAfterBuild() {
 
        for (Iterator it = trackerList.entrySet().iterator(); it.hasNext();) {
 
            ISqlMapTracker tracker = (ISqlMapTracker) it.next();
            tracker.afterSqlMapClientRebuild(sqlMapClient);
        }
    }
迭代模式和回掉模式的应用:
 
多么重复丑陋的小方法呀! ^_^ 我们仍然可以使用模式去让代码变得强壮起来:
    private void trackersWalker(ITrackerProcessor processor) {
        for (Iterator it = trackerList.values().iterator(); it.hasNext();) {
 
            ISqlMapTracker tracker = (ISqlMapTracker) it.next();
 
            processor.process(tracker);
        }
    }
   
    interface ITrackerProcessor{
       
        public void process(ISqlMapTracker tracker);
       
    }
 
    private void runTrackerBefore(final Object id, final IConfiguration unUse) {
        this.trackersWalker(new ITrackerProcessor(){
            public void process(ISqlMapTracker tracker) {
                tracker.beforeSqlMapConfigUnregistered(id, unUse);
            }});
    }
      
结束语
到这里,需求虽然已经实现,但是对代码的优化重构还远远没有结束。在项目中学到很多宝贵的经验,非常感谢leader-石鑫的指导。非常感谢!
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值