| 订阅 | 在线投稿
分享
 
 
 

利用反射实现类的动态加载(程序改正)

来源:互联网网民  宽屏版  评论
2006-12-04 21:03:22

原有的http://blog.csdn.net/bromon/上程序未能通过,本文增加之,谢谢原作者:

最近在成都写一个移动增值项目,俺负责后台server端。功能很简单,手机用户通过GPRS打开Socket与服务器连接,我则根据用户传过来的数据做出响应。做过类似项目的兄弟一定都知道,首先需要定义一个类似于MSNP的通讯协议,不过今天的话题是如何把这个系统设计得具有高度的扩展性。由于这个项目本身没有进行过较为完善的客户沟通和需求分析,所以以后肯定会有很多功能上的扩展,通讯协议肯定会越来越庞大,而我作为一个不那么勤快的人,当然不想以后再去修改写好的程序,所以这个项目是实践面向对象设计的好机会。

//首先定义一个接口来隔离类:

public interface Operator

{

// public java.util.List act(java.util.List params);

public java.util.List act(String content,String content2,java.util.List params);

}

根据设计模式的原理,我们可以为不同的功能编写不同的类,每个类都继承Operator接口,客户端只需要针对Operator接口编程就可以避免很多麻烦。比如这个类:

import java.util.*;

public class Success implements Operator

{

public static void main(String[] args) {

List list = new ArrayList();

list.add("Success3");

Operator op = new Success();

System.out.println("act===" + op.act("Success1", "Success2", list));

}

// public java.util.List act(java.util.List params)

public java.util.List act(String content, String content2,

java.util.List params) {

List result = new ArrayList();

result.add(content);

result.add(content2);

result.add(params);

return result;

}

}

同样,也可以写另一个类:

import java.util.*;

public class Load implements Operator

{

public static void main(String[] args) {

List list = new ArrayList();

list.add("Load3");

Operator op = new Load();

System.out.println("act===" + op.act("Load1", "Load2", list));

}

// public java.util.List act(java.util.List params)

public java.util.List act(String content, String content2,

java.util.List params)

{

List result = new ArrayList();

result.add(content);

result.add(content2);

result.add(params);

return result;

}

}

我们还可以写其他很多类,但是有个问题,接口是无法实例化的,我们必须手动控制具体实例化哪个类,这很不爽,如果能够向应用程序传递一个参数,让自己去选择实例化一个类,执行它的act方法,那我们的工作就轻松多了。

很幸运,我使用的是Java,只有Java才提供这样的反射机制,或者说内省机制,可以实现我们的无理要求。编写一个配置文件emp.properties:

#成功响应

1000=Success

#向客户发送普通文本消息

2000=Load

#客户向服务器发送普通文本消息

3000=Store

文件中的键名是客户将发给我的消息头,客户发送1000给我,那么我就执行Success类的act方法,类似的如果发送2000给我,那就执行Load类的act方法,这样一来系统就完全符合开闭原则了,如果要添加新的功能,完全不需要修改已有代码,只需要在配置文件中添加对应规则,然后编写新的类,实现act方法就ok,即使我弃这个项目而去,它将来也可以很好的扩展。这样的系统具备了非常良好的扩展性和可插入性。

下面这个例子体现了动态加载的功能,程序在执行过程中才知道应该实例化哪个类:

import java.lang.reflect.*;

import java.util.Properties;

import java.io.FileInputStream;

import java.util.List;

//这个程序是针对Operator编程的,所以无需做任何修改,直接提供Load和Store类,就可以支持2000、3000做参数的调用

//有了这样的内省机制,可以把接口的作用发挥到极至,设计模式也更能体现出威力,而不仅仅供我们饭后闲聊。

public class TestReflect

{

//加载配置文件,查询消息头对应的类名

private String loadProtocal(String header)

{

String result=null;

try

{

Properties prop=new Properties();

// FileInputStream fis=new FileInputStream("emp.properties");

// id = prop.getProperty(idString);

// prop.load(fis);

// fis.close();

prop.load(getTCL().getResourceAsStream("emp.properties"));

result=prop.getProperty(header);

}catch(Exception e)

{

System.out.println(e);

}

return result;

}

private static ClassLoader getTCL() throws IllegalAccessException,

InvocationTargetException {

Method method = null;

try {

method = Thread.class.getMethod("getContextClassLoader", null);

} catch (NoSuchMethodException e) {

return null;

}

return (ClassLoader)method.invoke(Thread.currentThread(), null);

}

//针对消息作出响应,利用反射导入对应的类

public String response(String header,String content,String content2,List list)

{

String result=null;

String s=null;

try

{

/*

* 导入属性文件emp.properties,查询header所对应的类的名字

* 通过反射机制动态加载匹配的类,所有的类都被Operator接口隔离

* 可以通过修改属性文件、添加新的类(继承MsgOperator接口)来扩展协议

*/

s="org.bromon.reflect."+this.loadProtocal(header).trim();

//加载类

System.out.println("s==="+s);//打印 s===org.bromon.reflect.Success

Class c=Class.forName(s);

//java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类

// Method m[] = c.getDeclaredMethods();//

// for (int i = 0; i < m.length; i++)//

// System.out.println(m[i].toString());

// 打印 public java.util.List org.bromon.reflect.Success.act(java.util.List)

//创建类的事例

Operator mo=(Operator)c.newInstance();

System.out.println("mo==="+mo);

//构造参数列表

Class params[]=new Class[3];

// params[0]=Class.forName("java.util.List");

params[0]=Class.forName("java.lang.String");

params[1]=Class.forName("java.lang.String");

params[2]=Class.forName("java.util.List");

System.out.println("params[0]==="+params[0]);

// //查询act方法

Method m=c.getMethod("act",params);

System.out.println("method=="+m.toString());

Object[] args=new Object[3];

args[0]=content;

args[1]=content2;

args[2]=list;

// //调用方法并且获得返回

Object returnObject=m.invoke(mo,args);//这个地方出问题了,抛异常~~~~

// System.out.println("returnObject==="+returnObject);

List result2 = (List)returnObject;

result = (String)result2.get(0);

System.out.println("result2=="+result2);

//

}catch(Exception e)

{

System.out.println("Handler-response:"+e);//Handler-response:java.lang.IllegalArgumentException: argument type mismatch

//IllegalArgumentException - 如果该方法是实例方法,且指定对象参数不是声明基础方法的类或接口(或其中的子类或实现程序)的实例;

//如果实参和形参的数量不相同;如果基本参数的解包转换失败;或者如果在解包后,无法通过方法调用转换将参数值转换为相应的形参类型。

}

return result;

}

public static void main(String args[])

{

TestReflect tr=new TestReflect();

List list = new java.util.ArrayList();

list.add("测试List");

tr.response("2000","Load1","Load2",list);//1000是Success,2000是Load

tr.response("1000","Success1","Success2",list);//1000是Success,2000是Load

}

}

测试一下,run一下TestReflect类,打印内容有,great!!

result2==[Load1, Load2, [测试List]]

result2==[Success1, Success2, [测试List]]

这个程序是针对Operator编程的,所以无需做任何修改,直接提供Load和Store类,就可以支持2000、3000做参数的调用。

有了这样的内省机制,可以把接口的作用发挥到极至,设计模式也更能体现出威力,而不仅仅供我们饭后闲聊.

 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
原有的[url=http://blog.csdn.net/bromon/]http://blog.csdn.net/bromon/[/url]上程序未能通过,本文增加之,谢谢原作者: 最近在成都写一个移动增值项目,俺负责后台server端。功能很简单,手机用户通过GPRS打开Socket与服务器连接,我则根据用户传过来的数据做出响应。做过类似项目的兄弟一定都知道,首先需要定义一个类似于MSNP的通讯协议,不过今天的话题是如何把这个系统设计得具有高度的扩展性。由于这个项目本身没有进行过较为完善的客户沟通和需求分析,所以以后肯定会有很多功能上的扩展,通讯协议肯定会越来越庞大,而我作为一个不那么勤快的人,当然不想以后再去修改写好的程序,所以这个项目是实践面向对象设计的好机会。 //首先定义一个接口来隔离类: public interface Operator { // public java.util.List act(java.util.List params); public java.util.List act(String content,String content2,java.util.List params); } 根据设计模式的原理,我们可以为不同的功能编写不同的类,每个类都继承Operator接口,客户端只需要针对Operator接口编程就可以避免很多麻烦。比如这个类: import java.util.*; public class Success implements Operator { public static void main(String[] args) { List list = new ArrayList(); list.add("Success3"); Operator op = new Success(); System.out.println("act===" + op.act("Success1", "Success2", list)); } // public java.util.List act(java.util.List params) public java.util.List act(String content, String content2, java.util.List params) { List result = new ArrayList(); result.add(content); result.add(content2); result.add(params); return result; } } 同样,也可以写另一个类: import java.util.*; public class Load implements Operator { public static void main(String[] args) { List list = new ArrayList(); list.add("Load3"); Operator op = new Load(); System.out.println("act===" + op.act("Load1", "Load2", list)); } // public java.util.List act(java.util.List params) public java.util.List act(String content, String content2, java.util.List params) { List result = new ArrayList(); result.add(content); result.add(content2); result.add(params); return result; } } 我们还可以写其他很多类,但是有个问题,接口是无法实例化的,我们必须手动控制具体实例化哪个类,这很不爽,如果能够向应用程序传递一个参数,让自己去选择实例化一个类,执行它的act方法,那我们的工作就轻松多了。 很幸运,我使用的是Java,只有Java才提供这样的反射机制,或者说内省机制,可以实现我们的无理要求。编写一个配置文件emp.properties: #成功响应 1000=Success #向客户发送普通文本消息 2000=Load #客户向服务器发送普通文本消息 3000=Store 文件中的键名是客户将发给我的消息头,客户发送1000给我,那么我就执行Success类的act方法,类似的如果发送2000给我,那就执行Load类的act方法,这样一来系统就完全符合开闭原则了,如果要添加新的功能,完全不需要修改已有代码,只需要在配置文件中添加对应规则,然后编写新的类,实现act方法就ok,即使我弃这个项目而去,它将来也可以很好的扩展。这样的系统具备了非常良好的扩展性和可插入性。 下面这个例子体现了动态加载的功能,程序在执行过程中才知道应该实例化哪个类: import java.lang.reflect.*; import java.util.Properties; import java.io.FileInputStream; import java.util.List; //这个程序是针对Operator编程的,所以无需做任何修改,直接提供Load和Store类,就可以支持2000、3000做参数的调用 //有了这样的内省机制,可以把接口的作用发挥到极至,设计模式也更能体现出威力,而不仅仅供我们饭后闲聊。 public class TestReflect { //加载配置文件,查询消息头对应的类名 private String loadProtocal(String header) { String result=null; try { Properties prop=new Properties(); // FileInputStream fis=new FileInputStream("emp.properties"); // id = prop.getProperty(idString); // prop.load(fis); // fis.close(); prop.load(getTCL().getResourceAsStream("emp.properties")); result=prop.getProperty(header); }catch(Exception e) { System.out.println(e); } return result; } private static ClassLoader getTCL() throws IllegalAccessException, InvocationTargetException { Method method = null; try { method = Thread.class.getMethod("getContextClassLoader", null); } catch (NoSuchMethodException e) { return null; } return (ClassLoader)method.invoke(Thread.currentThread(), null); } //针对消息作出响应,利用反射导入对应的类 public String response(String header,String content,String content2,List list) { String result=null; String s=null; try { /* * 导入属性文件emp.properties,查询header所对应的类的名字 * 通过反射机制动态加载匹配的类,所有的类都被Operator接口隔离 * 可以通过修改属性文件、添加新的类(继承MsgOperator接口)来扩展协议 */ s="org.bromon.reflect."+this.loadProtocal(header).trim(); //加载类 System.out.println("s==="+s);//打印 s===org.bromon.reflect.Success Class c=Class.forName(s); //java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类 // Method m[] = c.getDeclaredMethods();// // for (int i = 0; i < m.length; i++)// // System.out.println(m[i].toString()); // 打印 public java.util.List org.bromon.reflect.Success.act(java.util.List) //创建类的事例 Operator mo=(Operator)c.newInstance(); System.out.println("mo==="+mo); //构造参数列表 Class params[]=new Class[3]; // params[0]=Class.forName("java.util.List"); params[0]=Class.forName("java.lang.String"); params[1]=Class.forName("java.lang.String"); params[2]=Class.forName("java.util.List"); System.out.println("params[0]==="+params[0]); // //查询act方法 Method m=c.getMethod("act",params); System.out.println("method=="+m.toString()); Object[] args=new Object[3]; args[0]=content; args[1]=content2; args[2]=list; // //调用方法并且获得返回 Object returnObject=m.invoke(mo,args);//这个地方出问题了,抛异常~~~~ // System.out.println("returnObject==="+returnObject); List result2 = (List)returnObject; result = (String)result2.get(0); System.out.println("result2=="+result2); // }catch(Exception e) { System.out.println("Handler-response:"+e);//Handler-response:java.lang.IllegalArgumentException: argument type mismatch //IllegalArgumentException - 如果该方法是实例方法,且指定对象参数不是声明基础方法的类或接口(或其中的子类或实现程序)的实例; //如果实参和形参的数量不相同;如果基本参数的解包转换失败;或者如果在解包后,无法通过方法调用转换将参数值转换为相应的形参类型。 } return result; } public static void main(String args[]) { TestReflect tr=new TestReflect(); List list = new java.util.ArrayList(); list.add("测试List"); tr.response("2000","Load1","Load2",list);//1000是Success,2000是Load tr.response("1000","Success1","Success2",list);//1000是Success,2000是Load } } 测试一下,run一下TestReflect类,打印内容有,great!! result2==[Load1, Load2, [测试List]] result2==[Success1, Success2, [测试List]] 这个程序是针对Operator编程的,所以无需做任何修改,直接提供Load和Store类,就可以支持2000、3000做参数的调用。 有了这样的内省机制,可以把接口的作用发挥到极至,设计模式也更能体现出威力,而不仅仅供我们饭后闲聊.
󰈣󰈤
 
 
 
>>返回首页<<
 
 热帖排行
 
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
©2005- 王朝网络 版权所有