Java中利用ReflectionAPI優化代碼
摘要
開發者通過各種各樣的方法來嘗試避免單調冗余的編程。一些編程的規則例如繼承、多態或者設計模型可以幫助開發者避免產生多余的代碼。不過由于軟件開發方面存在著不確定性,因此這些規則并不能消除代碼維護和重新編寫的需要。在很多時候維護都是不可避免的,只有不能運作的軟件才是從不需要維護的。不過,這篇文章介紹了你可以使用Java的Reflection API的功能來減少單調的代碼編寫,并可以使用活動的代碼產生來克服reflection的限制。
數據配置(由外部的源頭得到數據并且將它裝載到一個Java對象中)可以利用reflection的好處來創建一個可重用的方案。問題是很簡單的:將數據由一個文件裝入到一個對象的字段中。現在假設用作數據的目標Java類每星期改變一次?有一個很直接的解決方法,不過你必須不斷地維護載入的過程來反映任何的改變。在更復雜的環境下,同樣的問題可能會令系統崩潰掉。對于一個處理過運用XML的大型系統的人來說,他就會遇到過這個問題。要編寫一個載入的過程通常是非常單調乏味的,由于數據源或者目標Java類的改變,你需要經常更新和重新編寫代碼。在這里我要介紹另一個解決方案,那就是使用映射,它通常使用更少的編碼,并且可以在目標Java類發生改變后更新自己。
最初,我想介紹一個使用Reflection在運行期間配置數據的方案。在開始的時候,一個動態、基于映射的程序要比一個簡單的方法更有吸引力多了。隨后,我要揭示出運行時Reflection的復雜性和冒險性。這篇文章將介紹由運行時的Reflection到活動的代碼產生。
由簡單到復雜
我的第一個方案使用一個載入類將數據從一個文件載入到對象中。我的源代碼含有對StringTokenizer對象下一節點方法的多次調用。在修改多次后,我的編碼邏輯變得非常的直接、系統化。該類構造了專用的代碼。在這個初始方案中,我只需要使用3個基本的對象:
1、Strings
2、Objects
3、Arrays of objects
你可以影射類的對象來產生代碼塊,如下表所示:
被影射來產生代碼塊的對象
Field type | Code block |
String | fileIterator.nextString(); |
Object[] | Vector collector = new Vector(); while(fileIterator.hasMoreDataForArray()){ Object data = initializeObject(fileIterator)collector.add(data); } Object[] objArray = new Object[collector.size()]; collector.copyInto(objArray); |
Object | initializeObject(fileIterator); |
我已經使用這個方案作了幾次編碼,因此我在寫代碼之前我已經知道該方案和代碼的結構。難點在于該類是變化的。類的名字、成份和結構在任何時候都可能發生變化,而任何的改變你都要重新編寫代碼。雖然會發生這些變化,但是結構和下載的流程仍然是一樣的;在寫代碼前,我仍然知道代碼的結構和成份。我需要一個方法,來將頭腦中的編碼流程轉換為一個可重用的、自動的形式。由于我是一個有效率的編程者,我很快就厭倦了編寫幾乎一樣的代碼,這時我想到了映射。
數據配置通常需要一個源到目的數據的影射。影射可以是一個圖解、DTD(document type definition,文檔類型定義),文件格式等。在這個例子中,映射將一個對象的類定義解釋為我們要映射的流程。映射可以在運行時復制代碼的功能。在需要重寫代碼時,我將載入的過程用映射來代替,它所需要的時間和重寫是一樣的。
載入的工程可以概括為以下幾步:
1、解釋:一個影射決定你在構造一個對象時需要些什么
2、請求數據:要滿足構造的需要,要進行一個調用來得到數據
3、拖:數據由源中得到。
4、推:數據被填充入一個對象的新實例
5、如果必要的話,重復步驟1
你需要以下的類來滿足以上的步驟:
.數據類(Data classes):由ASCII文件中的數據實例化。類定義提供數據的影射。數據類必須滿足以下的條件:
.它們必須包含有一個構造器來接收全部必需的參數,以使用一個有效的狀態來構造對象;
.它們必須由對象構成,這些對象是reflective過程知道如何處理的
.對象裝載器(Object loader):使用reflection和數據類作為一個影射來載入數據。產生數據請求。
.載入管理器(Load manager):作為對象裝載器和數據源的中介層,將對數據的請求轉換為一個數據指定的調用。這可以令對象載入器做到與數據源無關。通過它的接口和一個可載入的類對象通信。
.數據循環接口(Data iterator interface):載入管理器和載入類對象使用這個接口來由數據源中得到數據。
一旦你創建了支持的類,你就可以使用以下的聲明來創建和影射一個對象:
FooFileIterator iter = new FooFileIterator(fileLocation, log); LoadManager manager = new FooFileLoadManager(iter); SubFooObject obj = (SubFooObject)ReflectiveObjectLoader.initializeInstance(SubFooObject.class, manager,log); |
通過這個處理,你就創建了一個包含有文件內容的SubFooObject實例。