如何從職責和協作中發現豐富物件?

banq發表於2010-02-09
DDD領域驅動設計給我們指出統一建模統一語言的方向,從辨識角度提出區分實體和值物件的方法,如果說DDD只是給出了領域建模的方向,也就是WHAT部分,那麼,物件設計:角色、責任和協作"(Object Design: Roles, Responsibilities, and Collaborations)則更詳細地從HOW角度提出如何從職責和協作中發現並豐富物件。

從程式設計師角度來看:職責和協作是物件方法行為的兩種表現形式,物件內部行為稱為職責;物件之間互動行為稱為協作。但是職責和協作其實是物件內部行為或相互呼叫的來源,我們看到的程式碼往往是行為結果,為什麼物件中有這個方法行為,而不是那個物件行為,為什麼物件之間要有這種呼叫,為什麼不能放在一個物件中實現?

Martin Fowler曾經總結“重構”寫了一本書,書中羅列了很多重構方法,比如extract method,現在Eclipse工具重構refactor都有這些重構方法,但是在何種場景下使用這些重構方法?為什麼要將方法在物件之間遷移?如何能夠界定哪個方法行為和哪個物件更接近?如果我們從分析建模開始就引入職責和協作設計,一切都迎刃而解。

一個物件透過不同職責能夠扮演多個角色,從而實現不同業務場景情況下的業務功能,職責一旦複雜比較大,就會被切分,分配到兩個以上物件中,就形成了物件之間的協作。協作模型是描述“how” 和 “when” 和 “with whom.” 的動態行為,

軟體的互動協作使用如下Speak for Me軟體描述:
假設使用者是盲人或不能講話,躺在醫院病床上,她被囚禁了,不能用任何方式聯絡,除了眨眨她的眼睛,表“是”或“否”。她向Speak for Me發出字母訊息,軟體替代講話,用一個小的感測器監視她的眼睛眨,用來進行字母的選擇,並且能夠根據各自場景規則演算法猜測語句,供其選擇。她可以透過眨眼發出命令,比如眨眼發出”RE”讀取郵件,發出 “CH”尋求幫助。

該使用者是表達者,軟體是服務者,表達者驅動軟體為之服務,服務者隱藏了具體實現細節。如果我們隱藏了某個物件如何工作的實現細節,我們就可以在不影響使用者的情況下靈活地改變具體實現方式。

使用協作模型可以幫助我們分清WHAT和HOW,實現宣告式設計,達到DSM或DSL層面。

如果使用一群互相適合的物件在一起協作工作,支援一個大的職責,這是一個好的設計方式,DDD提出的聚合物件群也是這樣一個目的,兩者是一致的,下一步就是繼續關注物件是如何協作的,設計訊息(方法)執行步驟以及他們的引數和返回值。

通常有下面幾個職責和協作模式:
1.資訊擁有者模型,當一個物件是資訊擁有者,它的職責是知道這些資訊,不應該期望和其他物件協作獲得資訊。

有時資訊擁有者的職責將他們資料持久化(明確提出了物件自己實現自己儲存到資料庫是物件職責)
資訊是否被快取,如果修改如何更新,這是如何協作的?(明確提出物件自己負責自己快取是物件職責)。

比如:線上銀行的介面,接受交易資料,然後傳給服務的提供者,這個服務將其儲存在“交易記錄”這個物件中。
這裡僅有的協作者就是“交易記錄”物件自己使用持久層技術服務把自己儲存到硬碟上。

2.組織結構模型。類似UML中常提到的聚合和組合,專門有一個結構組織者(父物件)來管理它的部件,比如Car和發動機 方向盤就是聚合關係,Car負責管理部件間的結構,這類似部門經理管理部門一樣,和Facade模式非常相似。

除此之外,結構組織者(父物件)還要關心結構本身是否需要持久化?誰負責做這些持久化?這些物件是否被一個結構掌握訪問?結構是否組織隱藏物件之間關係?或者將其暴露給協作?其他物件是否知道這種組織並訪問?

這些提問就可以幫助你實現父子物件之間方法行為的分配,實現封裝和開放的OO設計原則。總之,一般是父物件知道自己子物件,就要使用結構模型。

另外,還有其他模型,比如:服務提供者模型,這類似於DDD中的服務模型,還有控制者模型和協作者模型:控制者能區分事情,決定採取行動;協作者通常是讓它做什麼就做什麼,很少做決定,有一個領導和部下,方向戰略和戰術的關係。

協作者模型和前面的結構者模型是有區別的,協作者模型側重管理一群工作者的行為,而結構者管理一群物件,表達一種它們之間的高聚合檢視。類似GoF設計模型中行為模式和結構模式的區別。

比如:當使用者在編輯一個文件時,選擇儲存,軟體在儲存到檔案之前必須做幾種決策,即將儲存的格式 (HTML, text, PDF, etc.)、是否取一個檔名?監視使用者行為動作的物件將直接響應這些決策,或在協作者之間分享決策。

本人以前在批判面向資料庫設計軟體時,就以文件編輯為例子,你只要發出儲存命令,而不必關心是如何儲存的,者實際又是一個WHAT(什麼命令)和HOW(如何執行命令)的關注分離。

此外,還有介面模型,如何定義介面,介面分使用者介面 內部介面和外部介面,介面封裝了職責和協作,因此,提倡面向介面程式設計不是隻是使用介面語法就可以,也不只是使用面向介面的框架就可以,這些都是表面的,真正的是用介面表達物件的職責和協作。

物件設計:角色、責任和協作"(Object Design: Roles, Responsibilities, and Collaborations)一書還提出了分層的職責,如下圖;DDD提出了分層架構,但是層的職責功能以及之間如何互動是什麼沒有詳細定義。

總之,如果你非常熟悉GoF設計模型,特別是其中的行為模式,很多方面和職責協作是相通的,如果有命令、事件、呼叫、訪問、通訊、觀察、監視等行為發生,我們就認為有協作發生,反之亦然。

[該貼被banq於2010-02-09 17:25修改過]

相關文章