反射的概念是由Smith在1982年首次提出的,主要是指程序可以訪問(wèn)、檢測(cè)和修改它本身狀態(tài)或行為的一種能力。
利用反射實(shí)現(xiàn)類的動(dòng)態(tài)加載
Bromon原創(chuàng) 請(qǐng)尊重版權(quán)
最近在成都寫一個(gè)移動(dòng)增值項(xiàng)目,俺負(fù)責(zé)后臺(tái)server端。功能很簡(jiǎn)單,手機(jī)用戶通過(guò)GPRS打開(kāi)Socket與服務(wù)器連接,我則根據(jù)用戶傳過(guò)來(lái)的數(shù)據(jù)做出響應(yīng)。做過(guò)類似項(xiàng)目的兄弟一定都知道,首先需要定義一個(gè)類似于MSNP的通訊協(xié)議,不過(guò)今天的話題是如何把這個(gè)系統(tǒng)設(shè)計(jì)得具有高度的擴(kuò)展性。由于這個(gè)項(xiàng)目本身沒(méi)有進(jìn)行過(guò)較為完善的客戶溝通和需求分析,所以以后肯定會(huì)有很多功能上的擴(kuò)展,通訊協(xié)議肯定會(huì)越來(lái)越龐大,而我作為一個(gè)不那么勤快的人,當(dāng)然不想以后再去修改寫好的程序,所以這個(gè)項(xiàng)目是實(shí)踐面向?qū)ο笤O(shè)計(jì)的好機(jī)會(huì)。
首先定義一個(gè)接口來(lái)隔離類:
package org.bromon.reflect;
public interface Operator
{
public java.util.List act(java.util.List params)
}
根據(jù)設(shè)計(jì)模式的原理,我們可以為不同的功能編寫不同的類,每個(gè)類都繼承Operator接口,客戶端只需要針對(duì)Operator接口編程就可以避免很多麻煩。比如這個(gè)類:
package org.bromon.reflect.*;
public class Success implements Operator
{
public java.util.List act(java.util.List params)
{
List result=new ArrayList();
result.add(new String(“操作成功”));
return result;
}
}
我們還可以寫其他很多類,但是有個(gè)問(wèn)題,接口是無(wú)法實(shí)例化的,我們必須手動(dòng)控制具體實(shí)例化哪個(gè)類,這很不爽,如果能夠向應(yīng)用程序傳遞一個(gè)參數(shù),讓自己去選擇實(shí)例化一個(gè)類,執(zhí)行它的act方法,那我們的工作就輕松多了。
很幸運(yùn),我使用的是Java,只有Java才提供這樣的反射機(jī)制,或者說(shuō)內(nèi)省機(jī)制,可以實(shí)現(xiàn)我們的無(wú)理要求。編寫一個(gè)配置文件emp.properties:
#成功響應(yīng)
1000=Success
#向客戶發(fā)送普通文本消息
2000=Load
#客戶向服務(wù)器發(fā)送普通文本消息
3000=Store
文件中的鍵名是客戶將發(fā)給我的消息頭,客戶發(fā)送1000給我,那么我就執(zhí)行Success類的act方法,類似的如果發(fā)送2000給我,那就執(zhí)行Load類的act方法,這樣一來(lái)系統(tǒng)就完全符合開(kāi)閉原則了,如果要添加新的功能,完全不需要修改已有代碼,只需要在配置文件中添加對(duì)應(yīng)規(guī)則,然后編寫新的類,實(shí)現(xiàn)act方法就ok,即使我棄這個(gè)項(xiàng)目而去,它將來(lái)也可以很好的擴(kuò)展。這樣的系統(tǒng)具備了非常良好的擴(kuò)展性和可插入性。
下面這個(gè)例子體現(xiàn)了動(dòng)態(tài)加載的功能,程序在執(zhí)行過(guò)程中才知道應(yīng)該實(shí)例化哪個(gè)類:
package org.bromon.reflect.*;
import java.lang.reflect.*;
public class TestReflect
{
//加載配置文件,查詢消息頭對(duì)應(yīng)的類名
private String loadProtocal(String header)
{
String result=null;
try
{
Properties prop=new Properties();
FileInputStream fis=new FileInputStream("emp.properties");
prop.load(fis);
result=prop.getProperty(header);
fis.close();
}catch(Exception e)
{
System.out.println(e);
}
return result;
}
//針對(duì)消息作出響應(yīng),利用反射導(dǎo)入對(duì)應(yīng)的類
public String response(String header,String content)
{
String result=null;
String s=null;
try
{
/*
* 導(dǎo)入屬性文件emp.properties,查詢header所對(duì)應(yīng)的類的名字
* 通過(guò)反射機(jī)制動(dòng)態(tài)加載匹配的類,所有的類都被Operator接口隔離
* 可以通過(guò)修改屬性文件、添加新的類(繼承MsgOperator接口)來(lái)擴(kuò)展協(xié)議
*/
s="org.bromon.reflect."+this.loadProtocal(header);
//加載類
Class c=Class.forName(s);
//創(chuàng)建類的事例
Operator mo=(Operator)c.newInstance();
//構(gòu)造參數(shù)列表
Class params[]=new Class[1];
params[0]=Class.forName("java.util.List");
//查詢act方法
Method m=c.getMethod("act",params);
Object args[]=new Object[1];
args[0]=content;
//調(diào)用方法并且獲得返回
Object returnObject=m.invoke(mo,args);
}catch(Exception e)
{
System.out.println("Handler-response:"+e);
}
return result;
}
public static void main(String args[])
{
TestReflect tr=new TestReflect();
tr.response(args[0],”消息內(nèi)容”);
}
}
測(cè)試一下:java TestReflect 1000
這個(gè)程序是針對(duì)Operator編程的,所以無(wú)需做任何修改,直接提供Load和Store類,就可以支持2000、3000做參數(shù)的調(diào)用。
有了這樣的內(nèi)省機(jī)制,可以把接口的作用發(fā)揮到極至,設(shè)計(jì)模式也更能體現(xiàn)出威力,而不僅僅供我們飯后閑聊。
?