關(guān)于 Vaadin / Hibernate 應(yīng)用開發(fā)的結(jié)構(gòu)的考慮
工具包應(yīng)該實(shí)現(xiàn)一個(gè)靈活的 FormFieldFactory。FormFieldFactory 根據(jù)一個(gè) context 來生成 Field,對 Field 進(jìn)行各種配置,并且將 Field 和 Property 進(jìn)行合理的連接,以便實(shí)現(xiàn) validate 和 type conversion等各種操作。FormFieldFactory 實(shí)際上做得很少,也沒有任何靈活性。靈活性全部在 context 中。具體而言,context 包含了上述配置信息和搭建/配置行為。配置信息方面,context包含了用來生成 Field 的各個(gè)相關(guān)元素(也就是下面要說到的默認(rèn)信息)以及用戶的指示等等。搭建/配置方面,context包含了具體實(shí)現(xiàn)的 command。通常是一個(gè) command chain,由用戶提供或者指定。但是,工具包應(yīng)該提供一個(gè)或者多個(gè)通用的 command,供用戶在大多數(shù)情況下使用。
主要的考慮有以下幾點(diǎn):
工具包提供的默認(rèn)行為應(yīng)該可以在大多數(shù)情況下滿足需要。
僅僅特殊的指示和特殊的操作需要用戶提供配置信息和操作的實(shí)現(xiàn)。
以上配置信息和搭建/配置行為應(yīng)該互相分開。
配置信息 / 搭建配置行為各自在一個(gè)適合的 / 集中的地方進(jìn)行配置,以便管理。
配置信息以及搭建/配置行為應(yīng)該靈活,容易擴(kuò)展。
關(guān)于配置信息的公開界面的考慮:
配置信息是要可以被各個(gè)搭建/配置行為的具體實(shí)現(xiàn)查詢到的。各個(gè)搭建/配置行為的具體實(shí)現(xiàn)會(huì)問這樣的問題:
我正在處理這個(gè)context(包含了正在為了哪一個(gè)form,哪一個(gè)Item,哪一個(gè)propertyId,來生成Field),希望獲得這樣的指示(比如,“Field 應(yīng)該用哪個(gè)具體實(shí)現(xiàn)類?”)。因此,界面可以是:
Context {
Object getConfigurationInfo(Object configurationType)
// 以下僅僅是為了免得客戶進(jìn)行類型轉(zhuǎn)換
String getStringConfigurationInfo(Object configurationType)
}
這樣,Context 會(huì)有很多具體代碼,但是省掉了各個(gè)搭建/配置行為具體實(shí)現(xiàn)去寫重復(fù)的代碼來或者這些關(guān)于Context的一些進(jìn)一步信息。
關(guān)于配置信息的考慮
配置信息分為默認(rèn)信息和特定指示信息。如果一個(gè)搭建/配置行為同時(shí)參考特定指示信息和默認(rèn)信息,應(yīng)該讓特定指示信息優(yōu)先于默認(rèn)信息。
默認(rèn)信息是本來就存在的,隨著業(yè)務(wù)模型或者UI等于生俱來的(比如業(yè)務(wù)模型的類的名稱,屬性的名稱等),或者雖然是用戶配置的信息,但不是專門為生成用戶界面而準(zhǔn)備的信息(比如hibernate 的元數(shù)據(jù))。默認(rèn)信息不需要配置或者至少不需要專門配置,因此可以很分散,總之讓搭建/配置程序可以得到即可。默認(rèn)信息應(yīng)該可以允許搭建/配置程序在多數(shù)情況下生成可以使用的,不需要進(jìn)一步修改的控件。
特定指示信息與默認(rèn)信息相反,是專門為了搭建/配置用戶界面而準(zhǔn)備的,應(yīng)該集中設(shè)置和管理,這樣比較方便查找和修改。特定指示信息應(yīng)該僅僅在特殊情況下用來進(jìn)行非常規(guī)配置(比如雖然業(yè)務(wù)模型是一個(gè)String類型的屬性,但是用選擇來進(jìn)行輸入),或者對默認(rèn)配置的進(jìn)一步修飾(比如默認(rèn)用選擇控件,但指示信息進(jìn)一步指示使用哪一樣選擇控件)。
指示信息應(yīng)該集中,從而方便管理。指示信息還應(yīng)該盡量通用,即不是僅僅為了某搭建/配置程序而準(zhǔn)備(雖然可能經(jīng)常如此),而是為了描述用戶所希望的結(jié)果。指示信息還應(yīng)該便于各個(gè)搭建/配置程序查詢。
關(guān)于默認(rèn)信息的具體考慮
FormFieldFactory 可以得到的各種信息都可以成為默認(rèn)信息的來源,它們包括:
Item - 在與 Hibernate 進(jìn)行結(jié)合的時(shí)候應(yīng)該是 BeanItem,那么 getBean() 可以得到 bean,進(jìn)一步可以得到其 class, Hibernate 的 metadata,以及一些標(biāo)記。這些 class, metadata 以及標(biāo)記應(yīng)該都可以作為智能生成 Field 的一些判斷。但是,bean 屬于model,不應(yīng)該過分地將表現(xiàn)層的東西(比如文本框的大小什么的)放到這里。如果某些屬性是與 model 相關(guān)而不因表現(xiàn)層改變的,比如密碼不論用什么表現(xiàn)層都應(yīng)該按照密碼輸入對待,那么在這里進(jìn)行標(biāo)注似乎是合理的。
id - BeanItem 使用屬性的名字作為 id,可以作為判斷條件,可以結(jié)合 bean 的類進(jìn)行判斷。
Form - 似乎沒有什么特別可以作為判斷條件的。但不妨作為參數(shù)傳遞給處理器。
默認(rèn)信息需要用代碼來獲得,具體實(shí)現(xiàn)可以先在 Context 上面來實(shí)現(xiàn),直接把獲得具體信息的代碼寫在 Context 上面。當(dāng)然,屬于對這些信息進(jìn)一步分析的代碼就應(yīng)該由具體的搭建/配置實(shí)現(xiàn)的代碼來完成了。
關(guān)于特定指示信息的具體考慮
特定指示信息應(yīng)該放在 context 里面,從而可以由所有的搭建/配置的具體實(shí)現(xiàn)單元參考。作為一種具體實(shí)現(xiàn),指示信息可以按照這樣的雙層方式組織:第一層是以作為信息類型的Object為索引的Map,第二層按照以下幾種方式查詢/設(shè)置(按照以下次序,最特殊的在前,最通用的在后,以解決沖突問題):
關(guān)于某 bean class / 某 property
關(guān)于某 property (這兩者都在 Context 里面有,因此完全可以 Context 自行得到)
僅僅在用到的時(shí)候?qū)崿F(xiàn):符合某種 condition - 使用一個(gè) condition framework (這個(gè)可以由用戶在指定)
關(guān)于搭建/配置行為的實(shí)現(xiàn)的考慮
為了使得這些行為盡可能得可以重用,這些行為應(yīng)該按照上面的配置信息(默認(rèn)信息以及特定指示信息)進(jìn)行動(dòng)作。
行為可以考慮用 chain of responsibility 模式實(shí)現(xiàn)。工具包提供很多行為的實(shí)現(xiàn)(command),還提供一個(gè)或者幾個(gè)一般用途的 chain 共用戶選擇使用。用戶也可以在具體應(yīng)用中提供特殊 chain,兩者進(jìn)行組合來實(shí)現(xiàn)。
關(guān)于具體的要完成的功能以及如何完成的考慮
要完成的功能 | 如何完成 |
生成 Form 中的 Field |
默認(rèn)行為和 Property 的類型有很大關(guān)系,比如 |
在 Field 之間和 pojo entity 之間進(jìn)行連接以及數(shù)據(jù)類型轉(zhuǎn)換 |
需要考慮 Field 在 commit() 的時(shí)候?qū)⒑畏N類型的值傳送給 datasource.setValue()。按照 AbstractField.commit()源代碼,應(yīng)該是getValue()。按照Field接口的文檔,getValue()的類型應(yīng)該是 getType()。因此,可以考慮以下實(shí)現(xiàn):
如果類型相符 - 就是說 field.getType() == datasource.getType(),可以直接連接,不需要進(jìn)行類型轉(zhuǎn)換。 如果類型不相符,則應(yīng)該連接一個(gè)類型轉(zhuǎn)化器,連接在兩個(gè) Property 之間。 converter.setValue() 接受 field.getType()類型參數(shù),然后進(jìn)行轉(zhuǎn)換,再調(diào)用 datasource.setValue()。反之,converter.getValue() 從 datasource.getValue() 取得值,然后進(jìn)行轉(zhuǎn)換,再返回給調(diào)用者。 converter 應(yīng)該實(shí)現(xiàn) property 接口。 默認(rèn)實(shí)現(xiàn)可以維護(hù)一組轉(zhuǎn)化器,自動(dòng)在 Field 和 data source 之間搭建類型轉(zhuǎn)換器。 |
對 Field 進(jìn)行裝飾 - 比如定義文本欄的尺寸大小,secret屬性,等等 | 默認(rèn)行為可以不進(jìn)行任何修飾或者進(jìn)行默認(rèn)修飾。其他的可以在特定指示中查找,如果有特定指示,則進(jìn)行修飾。 |
設(shè)置 Field 的 Caption | 默認(rèn)的實(shí)現(xiàn)可以將 bean name + property id 當(dāng)作鍵值,然后查找一個(gè)設(shè)定的 resource boundle。 |
對各個(gè) Field 的 validate |
默認(rèn)行為,可以查看是否 hibernate validate 或者其他 validation framework 的 validate 適用,如果適用,則生成一個(gè)對應(yīng)的 validator 適配器,進(jìn)行 validate。 |
對 form 進(jìn)行的 validate |
默認(rèn)行為:如果 form.getItemDataSource()是一個(gè)BeanItem,getBean返回一個(gè) hibernate 管理的 bean,可以自動(dòng)生成一個(gè)適配器 validator 給 form。 |
權(quán)限控制 |
根據(jù)用戶的 id, roles, 以及 bean/property id,自動(dòng)查找該用戶對應(yīng)的權(quán)限。 |
posted on 2010-01-06 11:41 bing 閱讀(752) 評論(0) 編輯 收藏 所屬分類: GUI