2013-03-07 62 views
3

背景設置有效地得到一個對象的屬性或強制執行類屬性的聲明

我試圖在Android的訪問和緩存Web服務數據創建一個圖書館和跨越問題都有所涉獵。

我的圖書館管理的所有對象都繼承自基類Entity類。任何派生類Entity可以聲明其他字段 *或屬性 *。

基類負責返回要從緩存(SQLite或文件)或Web服務(REST或SOAP)中讀取的Entity屬性。在我目前的實現中,Entity類使用反射來執行此操作:它讀取所有標記有@Attribute批註的類字段名稱。

問題

,我在我執行我遇到的問題是:每當我要求使用像static Set<String> getAttributes()功能全部Entity的屬性時,該功能必須創建一個Set實現(目前使用HashSet進行快速查找)。

我想避免每次請求所有屬性時分配和初始化Set<String>

從我的角度來看,屬性集特定於整個Entity類,而不是Entity對象。即:具有class Customer extends Entity,所有Customer實例具有相同的確切屬性 - 每個具有名稱,地址等。

我在這個當前的嘗試是聲明在每一個擴展Entitystatic Set<String> attributes,並在類的static塊這樣的使用反射初始化該Set

class Customer extends Entity 
{ 
    private static final Set<String> attributes = new HashSet<String>(); 

    static 
    { 
     Entity.populateAttributes(Customer.class); 
    } 
} 

由於類初始化時,Entity類可以查找在該類中標記爲@Attribute註釋的所有字段,並且它是基類(例如,Customer extends PersonPerson extends Entity將填充Customer.attributes集,該集具有爲Customer類聲明的屬性以及從繼承的屬性類)。

我遇到的問題是attributes集合可能沒有爲延伸Entity的類定義,我想在編譯時強制執行該集合。

我已經看到了這正在爲Serializable接口在Eclipse中完成的:當創建一個實現Serializable一個類時,Eclipse顯示一個警告,如果你的類不聲明[private] static final long serialVersionUID

問題

是否有我強制執行Serializable行爲我Entity類,並顯示警告或(更好的)一個錯誤,如果一個類沒有聲明的字段什麼辦法?

是否有不同的方法來返回屬性名稱爲Entity派生類?

腳註

* 我用了field於不應該由圖書館和應該由庫管理對象的屬性術語attribute被管理對象的屬性(可從Web服務讀或SQLite的/文件緩存和在web服務或SQLite的/文件高速緩衝存儲器)

EDIT 1

乙被持久asical,我試圖實現的是以有效的方式得到一組Entity的屬性*(見上面的腳註)。該列表由幫助類用於將對象值存儲在數據庫中(CREATE TABLE查詢可以從屬性名稱和類型推斷出)或發送到Web服務。

這個庫是用於從Web服務的緩存值和同步本地數據庫(其中可能包含額外的用戶輸入值和可能的對象缺少服務器更新後的值),通過Web服務訪問的數據。它不打算在具有通用訪問器/增變器的應用程序中替換每場訪問器/增變器的使用。

這個概念被稱爲鍵 - 值編碼和使用於許多框架和庫。舉個例子,我用Google搜索找到的使用KVC的庫的前兩個例子是Cocoa和Sproutcore。參考文獻:Apple developer documentationSproutcore wiki

KVC也用於Android開發。 Bundle,SQLiteCursorContentValues激烈使用KVC。

+0

「我的庫管理的所有對象都繼承自基礎實體類,任何派生類的實體都可以聲明其他字段*或屬性*。」或許這就是問題的核心。爲什麼不像其他人一樣使用數據成員,getter和setter?爲什麼要嘗試在Java之上構建自己的二流編程語言? – Raedwald 2013-03-07 13:15:54

+0

我正在這樣做,以便處理數據源對象序列化/反序列化的類可以做到這一點,而無需爲添加到應用程序的每個「實體」修改。另外,另一種方法(如果我將序列化/反序列化責任移動到「Entity」類):我希望能夠將序列化/反序列化類從JSON REST-ful服務切換到SOAP或XML REST-ful服務,而不必修改應用程序中的每個「實體」。 – 2013-03-07 13:20:27

+0

「我正在這樣做,以便處理數據源對象的序列化/反序列化的類可以做到這一點,而不必爲添加到應用程序中的每個實體修改」我會說這是尾巴搖擺狗。 Java是一種面向對象的編程語言:具有屬性,集合,關聯和增變器的設計對象。將序列化移入助手類。 – Raedwald 2013-03-07 13:23:42

回答

0

因爲我可能無法在派生類的定義中強制聲明靜態字段,所以我將通過在上述Entity類的定義中存儲屬性集和類描述的映射並確保派生類的屬性集在Entity構造函數中初始化。

舉個例子:

public class Entity 
{ 
    private final static Map<Class<? extends Entity>, Set<String>> attributes = new HashMap<Class<? extends Entity>, Set<String>>(); 

    public static void populateAttributes(Class<? extends Entity> derivedClass) 
    { 
     //initialize the set of attributes for the derived class and 
     //add it to attributes map with "derivedClass" as key 
    } 

    static 
    { 
     populateAttributes(Entity.class); 
    } 

    public Entity() 
    { 
     //calling this.getClass() returns the object's actual (derived) class(*) 
     if(!attributes.containsKey(this.getClass()) 
     populateAttributes(this.getClass()); 
    } 

    //rest of class definition (including getAttributes method) 
} 

public class Customer extends Entity 
{ 
    @Attribute 
    String someAttribute; //will be processed automatically 
} 

得到一個Entity小號屬性的成本將從解析所有的類屬性,以及創建一個新的集合他們堅持降低對Map檢查和檢索操作,其在使用HashMap時應該很小。

創建Entity實例的成本通過對屬性Map(在HashMap s上快速執行)進行檢查而增加。初始化給定類別的attributes集合的成本可以忽略不計,因爲每個派生類別類型只能執行一次。

考慮到該屬性要求至少一次每個類實例的場合的90%以上,這應該給比問題描述的初步解決方案更好的整體性能。

(*)的基類實例方法調用this.getClass()將返回對象的實際類。如果對象已被初始化爲派生類實例,則將返回派生類的描述(Class對象)。有關這方面的問題已在此處提出並回答:Which class does getClass() report inside a constructor of a base class