顯示具有 [D] 細部設計 標籤的文章。 顯示所有文章
顯示具有 [D] 細部設計 標籤的文章。 顯示所有文章

2007年9月8日 星期六

D28 細部設計的流程(Model)

在元件設計的階段裡,是將局部的功能需要以類似一個小型系統的方式加以設計。記錄下來的物件關係模型如下面附圖。流程與動作的主軸與基本觀念是一致的,但是Properties的輸入由ComponentImpl來使用;ComponentController使用的Component Model因為封裝而改由ComponentImpl傳來。

◎一個ComponentImpl由一個或一個以上的ComponentController組合而成
◎每個ComponentImpl使用一組Properties與一種ComponentModel
◎每個ComponentControllerl有一個或一個以上的ComponentAction(可能沒有)
◎每個ComponentController有可能傳回Return Code(可能沒有)
◎每個ComponentController都應該定義無法處理的Exception狀況(可能沒有)
◎每個例外狀況可以使用其他的ComponentAction或經由ComponentImpl拋出去註:這裡的Component也有可能是一段程式碼。


每個Component在設計時都有Class Diagram與Sequence Diagram,設計的同時每個Class都要定義屬性與方法,同時附上註解。Class會存在於Package(通常等同於Component的範圍),所以每個Package也會有一張Class Diagram來描述有哪些Class。

追溯關係則至少有三種:Component Controller與Component Action的使用關係。此外,訊息、參數與例外的內容應有清單與影響的關係追溯。
◎系統的目標:

2007年9月7日 星期五

D27 物件關係追溯的極致

現在想像一個Basic Data Model方法的內容需要修改,在我們的設計裡資料模組是所有元件與Controller使用的物件,所以我們必須重新測試系統所有的功能。這樣對嗎?只追溯物件使用的關係,的確只能這樣處理,事實上修改物件的一個方法時,應該只要確認那個方法被哪些物件在哪些方法裡使用,再往上搜尋所得的結果才是真正的影響。

在改變後為了確認所有被影響的動作都是否正常時,會因為只是物件層級的概略追溯而造成錯估真正的影響範圍,會付出比實際影響範圍超出許多的不必要測試之類的資源浪費。一個系統的在測試階段的問題單很可能上千張,如果每個問題的解決都或多或少地浪費了一些資源,累積起來到專案結束時總共有多少呢?

然而記錄得越詳細,所需要的資源的資源也會比較多,這時我們需要便利的追溯工具來減輕負擔。不要使用程式開發工具裡的追溯,因為層次一多,尋找的次數與內容也相對增加很多。在設計的同時其實使用關聯就已經存在於Design Model裡,只要有相對的工具可以便利地列出指定物件的追溯關係,這樣一來就方便許多。

2007年9月6日 星期四

D26 物件關係追溯的意義

每個物件在系統裡都有其存在的意義,也有與其他物件互動的關聯。追溯就是記錄物件與其他物件使用的所有關係。

一個物件所負責的動作或是處理邏輯因需求的變化或是發現錯誤的修正而有所改變時,都有可能連帶到影響使用它的其他物件;影響連帶地使上層物件有可能被改變,又再造成上一層其他物件可能被影響。如此循回下去,找出所有會使用到此物件的連帶關係。我們必須測試過使用關係裡的所有物件,才能保證這次的修改除了解決現有的問題之外,沒有再形成任何其他的問題。

有的時候我們需要把某個功能或物件獨立出來使用,這個情況我們需要知道往下使用了哪些物件,所以要從上往下尋找。以一個物件為中心,向下找出它使用的所有關聯物件,與向上找出會連帶使用它的所有關聯物件,就可以定義出它的影響範圍,這是每位從事軟體工程的人最基本的思考模式。

以自己的經驗來看,身邊的人會認真思考追溯關係的實在很少。工作上接觸的外國人士,像香港與新加坡,對於影響追溯的記錄追蹤相對地積極許多。

2007年9月5日 星期三

D25 追溯關係(3)──Package, Component & Class

在Rose Model裡,只要我們建立了物件與物件之間的關聯,那麼不管是在Rose的畫面或是SoDA產生的文件,都可以追溯到使用自己的物件與自己使用的物件。在Component View裡的所有物件與Diagram也是一樣。

從最上層來看,我們需要有全部的Package List與Package vs Package的水平追溯;接著要有每個Package vs Component的垂直追溯與Component vs Component的水平追溯;再往下還得有Component vs Class與Class vs Class的水平追溯。

對於一個元件來說,把元件內部的Class與Interface同時放到縱軸與橫軸,並於橫軸加上所使用到的其他元件Class與Interface,這是我們對於一個元件內部設計所應該追溯到的關聯範圍。

每一個物件的存在都有他所屬於的地方與他所擁有的物件,找出物件這一類的關聯存在是垂直追溯;物件本身在運作時會使用到的其他物件(應都是同樣層級),找出物件使用關聯的存在則是水平追溯。

2007年9月4日 星期二

D24 Component的使用關係──Component Diagram

設計元件的同時,時常會有動作需要使用其他已經開發完成的元件。雖然在Sequence Diagram與Class Diagram裡記錄了其他元件的Interface,但是若想知道使用一個元件時同時還需要“附帶”加上哪些元件才能運作正常的話,如果沒有記錄下來使用關聯,就絕對不是一時三刻內可以知道的。

想要快速地知道元件的使用關聯,同樣必須付出努力來記錄才能擁有這種效果;作法是在繪製UML Diagram時同時在Component Diagram記錄下元件間的關聯。首先建立放置元件的Package,Package的作用是library的界限,未來放置在同一個Package裡的所有元件實際上都會集合成一個library file 。這個時候先用一張Component Diagram放上所有的Package(先不要有使用關聯)。

接下來依序處理元件。首先要決定元件要放在哪一個Package裡,可以直接在Package節點上New Component並修改名稱。接著在Package裡新增一張Component Diagram,把所有Package裡的元件放進去,再逐一把使用到的其他Package元件放入並拉上使用關聯;與其他Package有關聯時,記得回到上一張圖拉起Package之間的關聯。


依序處理每一個Component與Package直到所有物件的位置與關係都正確為止。

2007年9月3日 星期一

D23 Component的設計產出──Sequence Diagram & Class Diagram

以介面定義作為規格的封裝元件,就像是一個獨立運作的小型系統。設計時以Implementation為起點,將元件的控製邏輯想法,逐一繪製成這兩張UML Diagram。

設計的想法與系統極為類似,我們可以把每個Interface方法視作一個Use Case,依元件每個層次應有的Interface先用Class Diagram標記出來,再用Sequence Diagram串接應該呼叫的方法,依這個原則完成所有方法的流程設計。這裡只需要處理正常執行的流程,因為錯誤的狀況都直接拋出Component Exception。

在設計時最重要的原則,是要把元件設計成絕對獨立的個體,進入Interface之後使用與傳遞的物件,除了執行環境的基本類別之外,就應該只能繼承與使用與開發的系統無關的類別。如此一來可以讓元件與系統之間除了被使用之外,完全沒有關聯存在;這也意味著日後可以把元件提供給任何一個系統來使用,而沒有之前系統的包袱。

在系統設計時如果使用到元件庫裡的元件,完全不用處理細部設計。因為該元件是已經開發完成而且已經通過測試。

2007年9月2日 星期日

D22 清單與項目(3)──集合與物件

物件本來是單獨的個體,但是當一堆相似的物件因為特定的目的而群聚在一起時,他們就應該受到集合管理。

集合是管理所有物件之處,我們需要取得特定物件時直接向對應的集合發出要求;發出的要求應含有想取得物件的篩選條件,集合則依條件傳回所有符合的物件實體;當然也應有列出集合內所有物件的方法。管理的動作還另外包含了新增物件與移除物件,控制者可以依實際狀況來增刪集合內物件的實體。

資源的管理有三個大類:目標與步驟是先有目標再將之切割為多個步驟,所有步驟成果的總和應等於目標的結果。清單與項目是先有項目再將之條列為清單,根據現在的所有項目產生清單的內容。集合與物件則是定義一個集合來管理所有物件,物件的增刪都被動地經由集合來操作。

群組與個體之間會有著使用或管理的動作,這同時表示著它們具有關聯,所以他們相互的影響都需要被追溯以應付未來可能有的任何改變。

2007年9月1日 星期六

D21 令人感到麻煩的設計(6)──解決循環使用的現象

在設計的經驗裡,總是會“不小心”遇到像左圖那樣循環使用的現象,這是需要極力避免的。因為當B改變的時候,要追溯到使用它的A,如果A因為B的改變也作了改變,那麼使用A的B又要再度改變而形成無窮迴圈。

最簡單的解法,就是把A拆成兩個Package,使用B的放在A1,被B使用的集中在A2,這樣就可以讓循環使用的現象變為圖中的單向使用。可是實際遇到的情況大多都因為Package的內聚力過高而無法乾淨地分為兩個Package。

嘗試了幾種有問題的方式後,我提出右圖的解法:在B裡定義一個A2功能的介面(注意:這個介面屬於B),A維持原來使用B的動作,但內部原本要分割成A2的部分使之實作B提供的介面,如此一來A使用B與A實作B都可以是由上往下的使用關係。

2007年8月31日 星期五

D20 令人感到麻煩的設計(5)──Abstract Class的設計

同樣的程式碼抽取到方法讓大家共用,同樣的方法抽取到共同的父類別來使用,這是設計中對於程式碼的reuse。
這是是一個簡單的繼承架構,ClassInterface下有一個DefaultClass作為基本實作類別,另外衍生了三個子類別。理論上DefaultClass應該會做出介面裡定義的全部動作,子類別在方法裡有不同的動作時再override(覆寫)父類別的的方法。

有的時候介面的方法很明顯地是該由各個子類別來決定如何實作,這個時候父類別就不可能有可以共用的方法實作。例如一個交通工具介面裡有move()方法,因為每種交通工具移動的方法不同,所以實作介面的基本類別,move()方法就應該保持為abstract等待子類別來實作。

會有人說:先隨便實作一個方法再由子類別override不是也可以嗎?設計時不該讓物件進行沒有必要的動作,不僅會令物件進行沒有定義的行為,同時不必要的override也讓程式更難追蹤。Abstract Class是無法產生實體的對應,只是對於物件的定義而不會變成物件;在意義上就像生物學裡的分類,界門綱目科屬種各定義了不同所屬物種的特徵,到最後的分類時(種)才有所有符合所有特徵定義的生物。

交通工具類別已經宣告move()為abstract,但是直接把汽車、輪船、飛機等直接繼承交通工具也會有問題,因為子類別裡還是會有多個類別有同樣動作的情形,一有改變就可能牽動到所有子類別。理想的設計是再衍成對應的分類類別,子類別再去繼承分類類別。一組類別要設計成這樣時比起快速地直接使用一個類別,當然會多花很多的時間,不過應做的工作還是該去做好的。

2007年8月30日 星期四

D19 令人感到麻煩的設計(4)──物件關係的影響

在B21裡提到了物件的三個關聯:is、has、use,其中關係最緊密的是is,其次是has、最鬆散的是use。

左圖的專案物件目前繼承CompClass2,在宣告的同時專案物件就永遠是一個CompClass2而不可能會變成其他種類,動作的時候就只能依CompClass2的規範。右圖的專案物件使用一個變數來記住內含的CompClassInterface,可以依需要操作設定的CompClassInterface實作(注意:三種CompClass都可以設定),這就增加了專案物件使用的彈性(Strategy Design Pattern)。

右圖的專案物件本身可以使用前一篇的方法繼承另一個Class,加上混用Wrapper Design Pattern讓專案物件同時實作CompClassInterface,並將實作方法全部直接呼叫strategy設定的CompClass的話,我們就可以擁有身具兩種CompClass的專案元件應用在更多的地方。(必要時還可以增加其他的strategy來擴充功能)

use是在呼叫時傳入物件,物件只在方法中使用而不另外記憶下來;在服務性質的API可以大量使用這種方式。呼叫Web Service時使用的就是這種物件關係。

2007年8月29日 星期三

D18 令人感到麻煩的設計(3)──吸收改變的避震器


上面這張圖的狀況是專案物件會廣泛地使用一個底層API。一開始我們很直覺地使用左圖裡的方式直接呼叫BasicAPI的方法,而且沒有遇到什麼問題;後來我們發現有些連續呼叫數個BasicAPI的方法在專案裡很常發生,需要抽出另外成為固定可用的API,於是我們建立了一個BasicAPIExt1,在遇到需要呼叫特定連續方法時使用新的BasicAPIExt1,其他情況則直接呼叫BasicAPI。

中間的圖我們可以看出,專案物件有些呼叫BasicAPI,有些則呼叫BasicAPIExt1,不僅層次的使用比較雜亂,每個專案物件有使用關聯的物件也變多了。設計該是具有層次與抽出共用部分簡化關係的,所以會用右圖的設計,讓BasicAPIExt1繼承BasicAPI來達到這些目的;而且未來BasicAPI的某些改變只會影響到BasicAPIExt1而不會影響到專案物件。

這個範例應用的範圍不只是API,應該包括專案所有使用(static method)或繼承關係的設計範圍。如果能夠費心把專案與元件之間的使用關係都加上一個類似避震器用途的類別(即使只是沿用也要加)的話,將會更輕易應付突然發生的改變。

2007年8月28日 星期二

D17 理論串接實作的瓶頸(9)──專案思維與元件思維

從系統的角度來看,需要呈現給使用者看到的是View、Model、顯示狀態的Message與處理中記錄的Log,會從系統外部來的有Properties與Model。元件如果像縮小的系統,是不是應該也要考慮這些與輸出入有關的物件呢?

我的答案是否定的。在前面我所切分的元件層次裡,主要有功能與功能的Controller、傳入的Properties、再加上一個Implementation用Factory處理功能的切換與用Wrapper把傳入的基本Model轉變為Component Model。View、Message與Log呢?它們只允許存在於系統?

元件應該是一個獨立的單位,它最重要的工作是完成我們需要的功能,並在無法處理時回報狀況與資訊。View的作用在於執行前輸入資料並於執行後顯示結果,這些資料其實都屬於Model的內容,元件只要能處理Model就可以工作;如果把View寫進元件裡頭,要是下一個系統使用的View不相容時應該又會是一樁慘劇。基於這個想法,元件也不應拋出提示的Dialog,我們可以規定功能的完整執行要進行三次呼叫,由上層的系統來控制每一次呼叫之中要做哪些提示動作。

Log的問題也很類似,把這個系統使用的Log物件傳入元件裡記錄,要是下次用的是另一個種類呢?Message則會牽涉內容的客製化與多國語言的問題,同樣不應該進入到元件裡面處理。每個元件的輸入Properties名稱與執行後的Message內容都應該設定成唯一存在的id,參數與資訊都使用代號後就可以在系統層級儘情地客製化為喜歡的樣子;當然,元件本身應該提供一個預設範本供系統直接使用或參考修改。

2007年8月27日 星期一

D16 Copy-Paste絕對不是Reuse

許多人在面對需要新增一項功能時,如果發現已經存在一個類似的時,心裡想到的必然是重覆使用已存在的,但是需求上有些微的差異必須實作,可是又擔心修改原有的會造成side effect。這時通常祭出的是copy-paste大法,快速“生出”另外一組程式碼,再隨心所欲的修改內容。

以功能需求來說,這樣做絕對是滿足功能的最快方式,同時也可以保證功能的測試很快完成。但是,即使用的是copy-paste,對於系統來說“全部”都是新增的程式碼,根據新增程式碼的作業流程所應該製作的文件、測試與追溯一個都不能少;雖然連這些都可以複製原來的,但是這樣的行為一多,整個系統類似的物件就會以等比級數來成長。

寫程式時若有方法需要擴充功能,大家都知道在同樣的方法裡增加參數讓它可以處理更多樣的情況;功能上的想法也應該是如此,在元件裡加上符合新增需求的方法或參數,努力想辦法讓元件支援更多種的功能。在分析與設計之後,動到的程式碼與copy-paste相差無多,但是只要修改原有文件而不用再“生出”一堆其他的文件。

copy-paste出來的產物,只能應付特定範圍內的“某些指定功能”;經由設計層次定位的元件,卻能夠應付特定範圍內的“所有功能”。在未來開發的時候遇到同樣特定範圍的功能時,前者還需要列出所有元件以供挑選哪一個適合,後者則直接掛上一個元件就滿足。同樣的道理,前者在library裡必須記錄全部的Component,後者就只有一個Component。

copy-paste到底是好是壞?想讓自己產出的元件是什麼樣子?你的決定將會影響到後人對自己的評價。

2007年8月26日 星期日

D15 令人感到麻煩的設計(2)──所有水平層次的設計

在設計每一個層次時,我們同樣也可能會遇到其他人送來的設計圖長得類似下圖。他想表達的是三個不同的元件各有其定義的介面與實作的入口類別。



不管我們怎麼決定設計,其實該有的東西都有的話系統應該都能正常做出來。但設計的目的除了讓每個物件各司其職之外,另一個重要的目的是要去蕪存菁,把重覆的程式碼集中到上一層的類別裡。上面的設計因為實作直接對應介面而沒有任何父類別,因而造成每個實作類別都得存放所有的程式碼在裡頭;那麼上一篇提到的介面基本方法就會到處都是。

理想的設計,還是必須多花一點功夫設計一個BasicCompInterface與BasicCompImpl來收集通用的屬性與方法,實際使用的元件繼承他們之後再撰寫自己的介面與實作。如果元件衍生時有因專案類型而適用在不同行業時,最好針對每一種專有的行業再設計一組對應的介面與實作,如此才能把不同的屬性與方法放置在他們應該存在的層級,而且可以快速篩選出適用特定行業的元件。

2007年8月25日 星期六

D14 理想Component介面的基本

思考到現在,心裡理想的Component介面的基本逐漸地成型。除了本身功能提供的方法之外,我認為要有以下幾種基本的通用方法:

public void setProperties(Properties properties)
public Properties getProperties()
設定參數集合與取得現有參數集合的方法,要不要有存取單一參數的方法則視需求而定。不過既然可以拿到集合,再從中取得指定的都不是問題。提供這組參數存取方法之外,也需要有文件列示所有的參數名稱與其影響。

public ComponentModelInterface getComponentModelInterface(BasicModelInterface basicModel)
Component傳入的Model是這個元件專用的。基於軟體工廠的想法,所以提供一個方法把基本Model傳入後會在裡面自動Wrapper成Component Model,接下來就可以任意地傳入Component裡來執行。

public List getAllMessageIDs()
public String getMessage(String messageID)
Component的訊息的內容應該由文件交待全部有哪些,或者有範例檔提供全部的訊息代號與預設的訊息內容供系統複製後修改。如果不想花時間另做文件的話,可以提供像這樣的API取得所有的訊息代號與其內容再存放到系統也不錯。

ComponentException
例外要使用Component自己專用的,每個具有無法處理或回復狀況的方法都應該定義成拋出Component Exception。

2007年8月24日 星期五

D13 令人感到麻煩的設計(1)──Data Model的設計

直覺地把系統的動作寫成程式是最快的開發方式,在執行上也很可能比較快。設計雖然也同樣地把同樣的系統動作寫為程式,但是多了很多與處理層次有關的類別,不僅在開發上相對緩慢,執行上也會因為呼叫的路徑變長而變慢些。


想像一下,我們是印表機延伸工具的開發廠商。依前面所談的,公司已經準備好Base Model作為基本資料類別,現在第一版系統要支援三款印表機。在一開始的Data Model設計有人提出了像上圖的方案,身為Leader的你應該通過這個Data Model設計嗎?

這個設計基本上當然可以讓系統正常執行(就算只用Basic Model也可以,但那會一團亂),然而設計的目標是讓系統的程式分門別類地形成層次。這裡的問題在於印表機延伸工具的系統,會定義出一些自己專用的資料與存取方法,以這個設計來看,那些專用的方法都必須實作在三組Data Model裡,不管是個別使用的或者是三種用法都相同的。

如果我們曉得要把重覆使用的程式區段抽取為方法來使用是正確的方式,那麼把重覆使用的方法再抽取到一個類別來reuse也是應該做的事情。雖然設計因此多加了一個層次,但是每個物件各司其職不作重覆的事,是OOAD所要表達的一個重要精神。

2007年8月23日 星期四

D12 IF介面像插座THAN Data Model是電力規格

在C07曾用機器人的可置換手臂來說明介面的用途,不過目前Interface最常比喻為插頭;不管各式各樣的電器,只要插頭符合插座的介面就可以插上去使用。現在世界上有四種最常見的插座規格,即使是種類不同的插頭,加上所謂的轉換器(Adapter Design Pattern)後還是可以插進去使用。

這是以可見的外觀來說明介面的用途,其實再深一層來說,插頭插上後還有在線路裡流動的電力;唯有提供電壓、電流的種類完全吻合的插座,才能夠正常地驅動電器。以元件的觀點來看,除了介面必須吻合之外,在介面上傳輸的Data Model也必須要能溝通才能動作。

外在的介面定義與內在的處理資料類型,這正是元件封裝之後留存給外界使用的規格。有時設計者為了偷懶,外部看得到的介面與資料定義得很詳細,封裝後看不到的內部就設計為寫死的黑箱,使用的時候因為功能都相同而沒任何感覺,可是一旦有問題或是需要改變,就讓接手的人痛苦萬分。這樣的行為,是不是“圖一己之便利,留後患給旁人”呢?

2007年8月22日 星期三

D11 Component的設計(5)──Exception & Properties

Component裡既然有自己的控制邏輯,那麼期待產生元件設計之初沒有預期到的狀況也是應該的。預期中的狀況可以在Component Controller裡判斷並控制,預期之外或無法處理的狀況就應該拋出Exception告知更上層的控制以便因應。

拋出的Exception應該是這個Component專有的,如此一來可以在層層呼叫的使用時,立即判斷出是在哪個Component裡出現的狀況,進而取得Exception裡的資訊作對應的處理。我們不該傳回基本型態的Exception,也不應與其他Component共用Exception,因為會搞不清楚到底是誰拋出同時也無法取到任何更進一步的資訊,尤其在共用Exception時更會加重使用的關聯。

Component的參數有些人會設計為Component特有的定義檔,在生成時讀取內容並設定。這種方式在設計上很直覺,但衍生的問題是每個Compoent都會擁有至少一個設定檔,當系統擁有上百個有設定檔的Component後,使用者若要調整一些設定就得逐一找到存放的地方打開編輯並儲存。

理想的作法是將所有Component的改變參數都設計傳入類似Properties的集合物件,每個Component的每個參數都擁有唯一的名稱作識別,使用只要建構時傳入或呼叫設定的方法就可以改變Component的設定。所有Component的Properties存放就經由系統統一管理,在需要設定Component時從集中管理的地方找到對應的Properties並傳入即可。

把Component的設定集中到系統管理的最大好處,其實是我們可以針對整個系統的可調整參數設計一個方便使用者編輯參數內容的編輯程式,就類似Windows的控制台的設計概念。

2007年8月21日 星期二

D10 理論串接實作的瓶頸(8)──實現軟體工廠的機會

前面提過所有功能的目的都在於處理資料,以封裝Component的概念來說,唯一的輸入與輸出物件就是Component Model。有很多人說過軟體工廠是不易實現的理想,假使工廠不管生產什麼樣的元件都是處理基本型態相同的Component Model,這樣一來是不是有機會實現呢?

上一篇提到在Model本質不同時有三種資料轉換的方式,每一種都需要另外撰寫程式才能讓資料在不同模組之間轉換:第一種必須寫存取資料的實作,第二種必須撰寫Wrapper程式,第三種則必須寫搬動資料的動作。如果,我是說如果,一間公司裡所有Component Model與Data Model的根本都是相同性質的基本資料類別(比如說是Map),每個Component的方法都附有一個方法將傳入的基本資料類別,包裝為Component Model後傳回再傳入Component處理,處理時對基本資料類別的所有操作都可以自動反應回系統。

2006年開發系統時加上了這個Common Model的想法,向下對應數種不同型態檔案讀回的內容,實際把檔案讀入後變為Common Model,實作時都是操作Common Model,使用者根據檔案類型呼叫對應的Parser後都是Common Model。Common Model再往上可分支實作出不同類型的Data Model給不同的系統使用,但是底層的處理都是通用的。利用這個概念應用在Model與Controller上,我讓兩個有點類似的系統共用了相同的處理核心,使得Use Case的再使用率達到70%以上。(註)

開發第二個系統的快速(花費人力大約佔第一個系統的五分之一)讓我對於軟體工廠的思維有相當大的信心。往後的專案只要先定義好公司使用的基本資料類別,我相信軟體元件化的理想是可以落實的。

註:開發的兩個系統是可以同時使用的,使用者可以自由切換到任一個系統執行任一個功能而不需重新啟動程式。

2007年8月20日 星期一

D09 Component的設計(4)──Model

與系統一樣Component應該有自己的Model。理由很簡單,如果Component操作時使用的Model屬於別的元件,那麼Component間會有使用關聯;如果Component使用的Model是簡單型的集合物件,又會因為加上基本存取動作而使得程式碼變得較難讀懂。

Component的定義與Class一樣需要高聚合與低耦合的封裝,為了減低與其他Component的關聯,定義出屬於自己的Model是勢在必行的。在設計時根據Component Controller的使用決定Model提供的方法並定義在ComponentModelInterface裡,即使是其他地方使用的Model只要實作這個Component指定的ComponentModelInterface就允許傳進來使用。

Component同時應該準備好ComponentModelInterface的基本實作給無法提供Model實作的程式使用,有些設計者會將許多Component集中使用同一種實作的Model而沒有定義ComponentModelInterface,這樣使得Component與Model緊密結合而無法改變使用其他實作的Model。

傳入Component的Model大致上有三類作法:第一種是直接讓系統使用的Data Model實作Component定義的Model Interface;第二種是使用Wrapper Design Pattern在生成ComponentModel的實作時把系統Data Mdeol包裝在裡頭;第三種則是設計一個轉換類別,在使用Component之前把Data Model的內容搬到ComponentModel並在使用後搬回來。