我最近在作某一个开源产品的项目,项目组的开发方式是敏捷开发+TDD。 java
项目场景:开发一套开源的持续集成环境,集成SVN、Jira、Hudson/Jenkins、Git、Trac、Sonar等,这些平台都是假设部署在Linux上,用java程序在各个平台上实现“建立项目”、“建立用户”、“分配角色权限”等功能。例如,经过编写java程序,在trac上建立一个项目,分配这个用户的某些权限 sql
我用测试先行的方式,先写测试样例,用最原始的方式为每一个方法(createProject,createRole)编写单元测试,这里说一下,在部署了Trac的Linux服务器上建立项目或角色等,都是经过Linux安装了Trac提供的命令实现功能,例如建立项目就是"trac-admin /usr/share/trac/projects/project1 initenv project1 sqlite:db/trac.db",建立角色并分配到某个默认权限的命令是"trac-admin /usr/share/trac/projects/project1 permission add role1 WIKI_ADMIN"。SVN也会有相似的实现方式,但其余平台可能未必是如此,多是经过服务器提供的接口来实现的。 设计模式
java链接Linux远程执行命令是使用第三方的jar,叫作"com.trilead.ssh2",经过创建Connection做为链接,用Session执行命令 服务器
在编写了单元测试并成功实现功能后,发现其实这两个功能的实现方式都是相同的,只是限于命令的不一样而已(事实上,经过TDD测试先行,有些时候会为开发实现带来不少方便之处,这里省略一万字……),为了让功能最大重用,分离变化点,把全部的执行都当作命令实现类(例如Trac建立项目叫作TracCreateProjectCommand类,Trac建立角色叫作TracCreateRoleCommand,如此类推),各自实现一个Command接口,命令接口的执行经过一个叫作CommandExecutor的类来负责,这样,一个有雏形的基于命令模式的设计模式初步呈现。 ssh
通过屡次代码实现和对应的单元测试后,再对各个Command接口实现类进行进一步封装,例如全部Trac相关的使用TracCommand抽象类执行操做,该类实现Command接口,同时做为TracCreateProjectCommand和TracCreateRoleCommand类的父类,该父类用于做为这两个子类的模板,封装了java远程SSH2的实现,子类只须要实现对应的返回命令方法便可。 单元测试
通过如此的封装后,从总体角度来看,外部调用CommandExecutor执行一条Command接口实现子类,执行对应的功能,此调用过程的设计理念是一个典型的命令模式。而命令实现类内部的模板实现方式,则是典型的模板方法模式 测试
最终的类图结构以下 spa