2009-04-23 33 views
0

我正嘗試在Java中編寫嵌入式(NOT web,而不是企業)內容管理系統,重點在於組織性,易用性和可擴展性,達到100,000個左右的項目。系統應該能夠創建和定義可以與唯一資源相關聯的元數據項目以允許搜索。如何爲具有可擴展屬性的資源編寫DAO?

例如,他們可以創建一個帶有String值的標籤「ProjectName」。然後,他們可以將一些資源標記爲屬於項目「掌控世界」或「修理我的車」。標籤是強類型的,所以標籤可以存儲單個或多個字符串,整數,雙精度等。每種標籤類型應該有格式化器和輸入驗證器以允許編輯。

我已經決定從GUI抽象存儲模型以允許可伸縮性是很重要的;執行此操作的顯而易見的方法是爲每個資源使用數據訪問對象(DAO)。但是,我不知道如何編寫支持可變數量標籤的DAO,並且可以正確縮放。

問題是資源需要表現爲元組(用於表格查看/排序/過濾)和(TagName,TagValue)地圖。 GUI模型可能會爲每次GUI更新調用這些方法數千次,因此一些索引的概念可以使其更好地工作。不幸的是,多重標籤類型意味着它會很笨拙,除非我將所有東西都作爲一個通用對象返回並且做了一堆「TagValue instanceof Type」條件。

我已經研究過使用反射和Apache的DynaBeans,但是編碼這個與GUI模型一起工作看起來很痛苦和尷尬。有一個更好的方法嗎???一些圖書館或設計模式?

所以,我的問題是,有沒有更好的方法?一些圖書館或設計模式,將簡單的整個事情?

回答

1

我不認爲你應該考慮任何這些屬性作爲實際的成員變量。你應該有一個「屬性」對象,它包含一個屬性(這將類似於一個成員變量)和一個具有屬性集合的「集合」對象(它將像一個類)。

由於這些屬性和集合真的沒有與它們相關的代碼,這將毫無意義,以實現它們的對象(將在屁股真正的痛苦)

你的屬性和集合需要保存所有特定於他們的數據。例如,如果一個字段最終寫入數據庫,它需要將表名存儲在某個地方。如果需要寫入屏幕,那也需要存儲在某個地方。

範圍/值檢查可以「添加」到屬性,因此當您定義屬性的數據類型時,可能會有一些文本顯示「MaxLength(12)」,它將實例化一個名爲MaxLength的類值12,並將該類存儲到屬性中。只要屬性的值發生變化,新的值就會被傳遞給已經應用到這個類的每個範圍檢查器。可以有多種與該課程相關的動作。

這只是基礎。我已經設計出這樣的東西,這是一個很好的工作,但它比試圖用一種直白的語言簡單得多。

我知道這看起來像是太多的工作了(它應該如果你真的得到我建議的),但記住它,最終你可能會去「哼,也許這是值得的嘗試畢竟「。

編輯(迴應評論):

我想過嘗試與註冊表/關鍵的事情(我們還在討論屬性值對)工作,但它不太適合。

您試圖將DAO放入Java對象中。這真的很自然,但我認爲這只是解決DAO/DTO問題的一種不好的方法。 Java對象具有對這些屬性起作用的屬性和行爲。對於你正在做的事情,沒有任何行爲(例如,如果用戶創建一個「生日」字段,你將不會使用目標代碼來計算他的年齡,因爲你不知道生日是什麼)。

所以,如果你拋棄了對象和屬性,你將如何存儲這些數據?

讓我走一個非常簡單的第一步(非常接近您提到的註冊表/標記系統):在哪裏使用對象,使用散列表。對於屬性名稱,使用鍵,對於屬性值,使用散列表中的值。

現在,我將介紹我用來增強這個簡單模型的問題和解決方案。

問題: 你已經失去了強類型,你的數據是非常自由的格式(這可能是壞的)

解決方案: 作出「屬性」基類中的場所使用散列表中的值。擴展IntegerAttribute,StringAttribute,DateAttribute,...的基類不要允許不適合該類型的值。現在你已經擁有了強大的輸入,但它是運行時而不是編譯時 - 可能沒問題,因爲你的數據在運行時實際上是DEFINED的。

問題: 格式化程序和驗證程序

解決方案: 必須創建一個插件爲您的屬性基類的能力。您應該可以爲任何屬性設置「setValidator」或「setFormatter」。驗證器/格式化程序應該使用該屬性 - 因此,當您保存屬性時,您可能必須能夠將它們序列化到數據庫。

這裏很好的一點是,當你在屬性上執行「attribute.getFormattedValue()」時,它已經預先格式化顯示。如果任何驗證失敗,attribute.setValue()將自動調用驗證器並拋出異常或返回錯誤代碼。

問題: 如何在屏幕上顯示這些信息?我們已經有了getFormatted(),但它在屏幕上顯示的是什麼?我們用什麼標籤?什麼樣的控件應該編輯這個字段?

解決方案: 我會將所有這些東西存儲在每個屬性中。 (順序應該存儲在類中,但是因爲這是一個哈希表,所以它不會工作 - 那麼我們會在下一步)。如果您存儲顯示名稱,用於呈現此內容的控件類型(文本字段,表格,日期...)和數據庫字段名稱,則此屬性應具有它需要與顯示和數據庫I/O例程編寫來處理屬性。

問題: 該Hashtable是一個糟糕的DAO接口。

解決方案: 這是絕對正確的。你的散列表應該被包裝在一個知道它所擁有的屬性集合的類中。它應該能夠將自身(包括其所有屬性)存儲到數據庫 - 可能需要輔助類。它應該可以通過一個方法調用來驗證所有的屬性。

問題: 如何實際使用這些東西?

解決方案: 由於它們包含自己的數據,因此它們在系統中任何與它們交互的地方(比如屏幕或數據庫)都需要一個「適配器」。

假設您正在展示一個屏幕來編輯您的數據。您的適配器將傳遞一個框架和一個基於散列表的DTO。

首先它會按順序遍歷屬性列表。它會問第一個屬性(比如一個字符串)它想要用來進行編輯的控件類型(比如文本字段)。

它會創建一個文本字段,然後它會將一個偵聽器添加到將更新數據的文本字段,這會將您的數據綁定到屏幕上的控件。

現在只要用戶更新控件,更新就會發送到屬性。該屬性存儲新值,你就完成了。

(這將通過一個「OK」按鈕,所有的值在一次遷移的概念很複雜,但我仍然會設專人之前每個綁定,然後使用「OK」作爲觸發。)​​

這種綁定可能很困難。我用手工完成了這個工作,一旦我使用了一個名爲「JGoodies」的工具包,這個工具包內置了一些綁定功能,這樣我就不必親自編寫每個可能的綁定組合,但是我不確定從長遠來看它節省了很多時間。

這太長了。我將在某一天創建一個DAO/DTO工具包 - 我認爲Java對象完全不適合作爲DAO/DTO對象。

如果您仍然難住,請隨時Email/IM me - billmail在gmail ..

0

您是否使用關係數據庫綁定?研究面向文檔的數據庫(如couchDB)可能是值得的。它會給你靈活性,你需要存儲你想要的任意強類型對象,並且還可以讓你查詢這些對象。我相信還有一些用於訪問couchDB的Java庫。

+0

我不想與任何特定系統緊密聯繫,但我已經在考慮使用Apache Jackrabbit作爲後備存儲。我大多需要一個很好的DAO模型來表達一個好的通用接口。 – BobMcGee 2009-04-23 20:01:05

+0

我對Jackrabbit並不熟悉,但看起來它實現了Java內容庫規範。該規範應該爲您提供通用節點,屬性等API。至於DAO,看起來Spring對JCR有很好的支持,並且使用它們的框架實現了DAO: https://springmodules.dev.java。 net/docs/reference/0.6/html/jcr.html – Andrew 2009-04-23 20:11:42

1

我從你的問題中假設一個「資源」是你的系統中有一些與它關聯的「標籤」實體的實體。如果我的假設是正確的,這裏的香草DAO接口,讓我知道,如果這是你在想什麼:

public interface ResourceDAO { 
    void store(Resource resource); 
    void remove(Resource resource); 
    List<Resource> findResources(QueryCriteria criteria); 
    void addTagsToResource(Resource resource, Set<Tag> tags); 
} 

這裏的想法是,你會實現這個接口的任何數據存儲機制,你有可用的,並且應用程序將通過此接口訪問它。實現類的實例將從工廠獲得。

這是否符合你的想法?

您提到的問題的另一方面是需要根據類型(需要「TagValue instanceof Type」條件)需要與需要不同行爲的多個不同TagType進行競爭。 Visitor pattern可以以優雅的方式爲您處理。

+0

Visitor模式對於處理多態和可插入顯示/處理/驗證聽起來很有用,我正在研究它。 您的DAO模型與我正在考慮的存儲接口非常相似,但我想知道您認爲Resource對象在接口方面會是什麼樣子。 – BobMcGee 2009-04-27 15:30:38