万能调节器(Universal adapter)的设计与实现
-Factory, Singleton, Adapter和Reflection的应用
本文的目的是设计并实现一个工厂(Factory),可以通过配置文件adapter-config.xml,生成配置文件内定义的Adapter的实例,每个Adapter又可以灵活的调用任何一个类的多个方法。
1.设计
UML类图如下:

UniversalFactory类负责创建Adapter实例,它是一个Singleton类,调用CreateInstance静态方法实例化该工厂类,并根据adapter-config.xml的内容初始化Adapters,然后调用getUniversalAdapter方法获得某个Adapter实例。
Adapter-config.xml文件内容如下:
<adapters>
<adapter name="scm" class="com.ibm.issc.universal.SCMAdapter">
<config file="E:/MyProject/UniversalAdapters/UniversalAdapters/config/scm-config.xml"/>
</adapter>
<adapter name="office" class="com.ibm.issc.universal.OfficeAdapter">
<config file="E:/MyProject/UniversalAdapters/UniversalAdapters/config/office-config.xml"/>
</adapter>
</adapters>
每个Adapter必须继承UniversalAdapter抽象类,该抽象类又实现UniversalInterface接口,UniversalInterface接口有唯一的一个方法execute供用户调用。每个Adapter还必须实现UniversalAdapter的一个init抽象方法,该方法负责读入adapter的config文件,例如scm-config.xml和office-config.xml文件,并根据config文件实例化Adaptee类,adaptee可以是任意类。例如图中的VSSAdaptee,WordAdaptee。
Adapter的config文件如下:
<scms>
<scm name="vss" class="com.ibm.issc.adaptee.VSSAdaptee" stateful="false">
<tasks>
<task id="login" method="login">
<param name="userid" value="zhaolei"/>
<param name="pass" value="zaq12wsx"/>
<param name="root" value="//9.186.27.239/vss"/>
</task>
<task id="checkout" method="checkout">
<param name="project" value="input"/>
<param name="target" value="c:/inputsrc"/>
</task>
</tasks>
</scm>
<scm name="cvs" class="com.ibm.issc.adaptee.CVSAdaptee" stateful="true">
<tasks>
<task id="login" method="login">
<param name="userid" value="zhaolei"/>
<param name="pass" value="zaq12wsx"/>
<param name="root" value="//9.186.27.239"/>
<param name="path" value="c:/cvspath"/>
</task>
<task id="checkout" method="checkout">
<param name="project" value="input"/>
<param name="target" value="c:/inputsrc"/>
</task>
</tasks>
</scm>
</scms>
当用户调用Adapter的execute方法时,需要传入需要想要调用的Adaptee的id,该id保存在config文件中的<task>里。
一个使用该工具的例子:
//工厂的实例化
UniversalFactory.CreateInstance(
"E:/MyProject/UniversalAdapters/UniversalAdapters/config/adapter-config.xml");
//获得关于scm的Adapter实例。即com.ibm.issc.universal.SCMAdapter的实例。
UniversalInterface _inter>getUniversalAdapter("scm");
String[] ids={"cvs","vss"};
//执行cvs和vss的Adaptee里所有在scm-config.xml文件<task>定义的方法,即cvs的login和checkout,以及vss的login和checkout
_interface.execute(ids);
2.实现
文本采用了工厂模式,单体模式,调节器模式和Java的反射机制。
2.1 工厂类的实现-工厂模式和单体模式
UniversalFactory类内保存所有Adapter的实例,它是一个单体模式和工厂模式类。
/**
* Universal Factory that creates instances of adapters.
* @author tyrone
*
*/
public class UniversalFactory {
//保存所有Adapter
private static HashMap adapters=new HashMap(10);
//工厂实例
private static UniversalFactory factory;
//单体模式
private UniversalFactory(){
}
/**
* Create instance of itself.
* initialize adapters that are saved in factory.
* @param configxml
* @throws UniversalFactoryException
*/
public static void CreateInstance(String configxml)
throws UniversalFactoryException{
if(factory==null){
factory=new UniversalFactory();
}
//解析adapter-config.xml文件。XMLAdapterProcess的实现略。
XMLAdapterProcess process;
try {
process = new XMLAdapterProcess(configxml);
} catch (XMLException e) {
throw new UniversalFactoryException(e);
}
List infos=process.getInfos();
int size=infos.size();
if(size==0)
{
throw new UniversalFactoryException("No adapters");
}
int i;
for(i=0;i<size;i++){
Object o=infos.get(i);
if(!(o instanceof XMLAdapterInfo)){
throw new UniversalFactoryException("Adapter info error");
}
XMLAdapterInfo adapterInfo=(XMLAdapterInfo)o;
try {
//实例化Adapter。
UniversalAdapter adapter=(UniversalAdapter)Class.forName(adapterInfo.getClassName()).newInstance();
if(adapter==null){
throw new UniversalFactoryException("adapter instantiate error");
}
//调用Adapter的init方法,初始化Adapter。
adapter.init(adapterInfo.getClassName(), adapterInfo.getConfig());
//将Adapter实例保存到HashMap。
adapters.put(adapterInfo.getName(),adapter);
} catch(UniversalAdapterException e){
throw new UniversalFactoryException(e);
} catch (InstantiationException e) {
throw new UniversalFactoryException(e);
} catch (IllegalAccessException e) {
throw new UniversalFactoryException(e);
} catch (ClassNotFoundException e) {
throw new UniversalFactoryException(e);
}
}
}
/**
* get specified adapter
* @param name
* @return
* @throws UniversalFactoryException
*/
public static UniversalInterface
getUniversalAdapter(String name)
throws UniversalFactoryException{
//从HashMap中获得Adapater实例。
Object adapter=adapters.get(name);
if (adapter ==null){
return null;
}else if(!(adapter instanceof UniversalInterface))
{
throw new UniversalFactoryException("Adapter:"+
name + " is not compatible");
}
return (UniversalInterface)adapter;
}
}
2.2 调节器类的实现-Adapter模式和反射机制
SCMAdapter负责实例化scm-config.xml文件中定义的class,并在SCMAdapter的execute方法中调用scm-config.xml文件中定义的各个<task>中的method。使用Java反射机制动态调用method。
public class SCMAdapter extends UniversalAdapter {
//解析scm-config.xml。实例化adaptee。
public void init(String id, String config) throws UniversalAdapterException {
this.id=id;
this.setSession(new SCMSession());
try {
XMLSCMProcess process=new XMLSCMProcess(config);
List infos=process.getInfos();
int size=infos.size();
if(size==0)
throw new UniversalAdapterException("no adaptee");
int i;
for(i=0;i<size;i++){
Object o=infos.get(i);
if(!(o instanceof SCMInfo))
throw new UniversalAdapterException("adaptee info error");
SCMInfo scmInfo=(SCMInfo)o;
try {
//实例化Adaptee。
Object adaptee=Class.forName(scmInfo.getClassName()).newInstance();
//保存到Session。
this.getSession().setAdaptee(scmInfo.getName(), adaptee);
//保存task。
this.getSession().setTask(scmInfo.getName(), scmInfo.getTasks());
} catch (InstantiationException e) {
throw new UniversalAdapterException(e);
} catch (IllegalAccessException e) {
throw new UniversalAdapterException(e);
} catch (ClassNotFoundException e) {
throw new UniversalAdapterException(e);
}
}
} catch (XMLException e) {
throw new UniversalAdapterException(e);
}
}
public SCMAdapter(){
//read configXml
String config=this.getCongigXml();
//init scm adaptees.
}
/*执行tasks
*/
public Object[] execute(String[] id) throws UniversalAdapterException {
int size=id.length;
int i;
List result=new ArrayList();
for(i=0;i<size;i++){
//从Session中获得Adaptee
Object adaptee=this.getSession().getAdaptee(id[i]);
//获得tasks
TaskInfo[] tasks=this.getSession().getTasks(id[i]);
int l;
//执行tasks
for(l=0;l<tasks.length;l++){
System.out.println("Adaptee:"+id[i]+" execute:"+tasks[l].getId());
//获得method所需所有参数。
Object[] args=tasks[l].getParams();
int psize=args.length;
Class[] paramsType=new Class[psize];
int k;
//参数类型都为string
for(k=0;k<psize;k++){
paramsType[k]=String.class;
}
try {
//java反射,获得method对象。
Method method=adaptee.getClass().getMethod(tasks[l].getMethod(),paramsType);
//invoke方法。将结果返回Result。
result.add(method.invoke(adaptee,args));
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
throw new UniversalAdapterException(e);
} catch (NoSuchMethodException e) {
throw new UniversalAdapterException(e);
}
}
}
return result.toArray();
}
}
3.结果
定义一个Adaptee,名为VSSAdaptee
/**
*statelessadaptee
*@authortyrone
*
*/
publicclass VSSAdaptee{
public VSSAdaptee(){
}
//登录
publicvoid login(String userid,String pass,String database) throws VSSException{
System.out.println(this.getClass().getName()+"login:"+userid+","
+pass+","+database);
}
//checkout
publicvoid checkout(String project,String target){
System.out.println(this.getClass().getName()+"checkout:"+project+","
+target);
}
//推出
publicvoid logout(){
System.out.println(this.getClass().getName()+"logout:");
}
}
Scm-config.xml中VSSAdaptee的配置信息如下:
<scm name="vss" class="com.ibm.issc.adaptee.VSSAdaptee" stateful="false">
<tasks>
<task id="login" method="login">
<param name="userid" value="tyrone"/>
<param name="pass" value="zx"/>
<param name="root" value="//19.186.27.239/vss"/>
</task>
<task id="checkout" method="checkout">
<param name="project" value="input"/>
<param name="target" value="c:/inputsrc"/>
</task>
</tasks>
</scm>
该任务将执行login,checkout,然后logout。
运行测试程序:
publicclass UniversalFactoryTest {
/**
*@paramargs
*/
publicstaticvoid main(String[] args) {
try {
UniversalFactory.CreateInstance(
"D:/MyProject/colimas/universal/UniversalAdapters/config/adapter-config.xml");
UniversalInterface _inter>getUniversalAdapter("scm");
String[] ids={"vss"};
_interface.execute(ids);
} catch (UniversalAdapterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UniversalFactoryException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
结果如下:
Adaptee:vss execute:login
com.ibm.issc.adaptee.VSSAdapteelogin:tyrone,zx,//19.186.27.239/vss
Adaptee:vss execute:checkout
com.ibm.issc.adaptee.VSSAdapteecheckout:input,c:/inputsrc
Adaptee:vss execute:logout
com.ibm.issc.adaptee.VSSAdapteelogout: