顯示具有 [C] 架構設計 標籤的文章。 顯示所有文章
顯示具有 [C] 架構設計 標籤的文章。 顯示所有文章

2007年8月11日 星期六

C30 架構設計的流程(Model)

在需求階段裡,藉由訪談客戶獲取系統需求加以分析並記錄。記錄下來的物件關係模型如下面附圖。圖中物件間的關係如下:與A19的基本概念模型比較,會發現他們的本質上是相同的。

◎一個Use Case Flow由一個或一個以上的Service組合而成
◎每個Service有一個或一個以上的Properties與Input
◎每個Service有可能傳回Return Code(可能沒有)
◎每個Component都應該定義無法處理的Exception狀況(可能沒有)
◎每個例外狀況都要有一個或一個以上以上可能的其他Service
◎一個其他Service由一個或一個以上的Component組合而成註:這裡的Component也有可能是一段程式碼。


每個Use Case Realization在設計時都有Class Diagram與Sequence Diagram,設計的同時每個Class都要定義屬性與方法,同時附上註解。Class會存在於Package,所以每個Package也會有一張Class Diagram來描述有哪些Class。

追溯關係則至少有三種:Use Case與系統Class、系統Class彼此間、系統Class與元件Class的使用關係。此外,訊息與參數的內容應有清單與影響的關係追溯。

2007年8月10日 星期五

C29 理論串接實作的瓶頸(7)──Use Case vs. Class & Class vs. Class的追溯

很多人在一聽到要做這兩層的追溯關係時頭都很痛,因為一個系統動不動就幾百個甚至上千個類別,Use Case也差不多都近百個起跳。光是Use Case對Class就已經是一百對一千的表格了,更何況Class對Class的一千對一千大型表格呢?而且,所有的關連都建立在程式碼裡頭。

如果有這樣的想法,那很肯定這些人是沒有設計層次概念的。雖然實際使用的類別有一千個,但是經由層次的定義,我們可以劃分哪些屬於系統架構設計層次的類別,哪些屬於更下層元件層次的類別。如此一來,Use Case要找的是與架構設計類別的垂直關係(A),架構設計再找出與元件類別的垂直關係(B),另外再加上架構設計類別裡彼此的水平使用關係(C)而已。

A與B的關聯在建立Use Case Realization與繪製裡面的圖表時已經將之設定在rose model裡,經由SoDA可以快速找到。雖然C的關聯也同時被放在圖表裡,但是我們可以經由Package名稱的篩選區隔出系統與元件的區別。系統設計的類別會放在與系統相關的Package裡,元件則基於全公司共用的規則放在不同等級的Package之下,由這個差異我們可以定出類別所屬的不同層級。

應用層次的落差使用較多層次的對應關係來達到像粽子一樣,提起Use Case後可以往下找出所有有關的類別是這裡的關鍵;這樣一來就可以免除開頭所說的那種勾選超大型表格的惡夢。

2007年8月9日 星期四

C28 追溯關係(2)──Use Case vs. Class & Class vs. Class

每個Use Case的功能都是由一群Class合作完成的,這表示著Use Case與Class之間存在著使用的關聯;也就是說在這裡同樣得做好使用關係的追溯。反過來看時,Class參與了哪些Use Case的完成也是必須追溯的關聯。

在架構設計的時候,產生的物件都屬於前面架構各層級的設計,對應的是需求分析的結果,除了使用元件的Interface之外,其他的Class都是與系統直接相關的物件。對於分層設計的概念來說,元件與Service是屬於不同層級的物件,所以不建議追溯時混在一起。

既然設計分了層次,追溯就無可避免地也分對應的層次。在Use Case對Class這層的關係就對應到與系統需求有關的Class;在更為精細的追溯時,追溯的對象會細分到Class裡的變數與方法,這樣可以在修正與變更時能夠更詳細地定位哪些地方需要重新測試。

在SoDA的應用上,我們可以取得所有的Use Case Realization,進而拿到裡頭所有的Class Diagram與Sequence Diagram,再依序條列出圖裡所用到的全部Class,很容易地就可以取得每一個Use Case有關聯的所有Class。

再下一層是系統Class對應使用元件Class的追溯關係。在這裡我們必須要能知道每個系統Class使用了哪些元件Class,同樣地也應該知道元件被應用在哪些系統程式裡。表面上雖然是平等的Class vs. Class,但是在設計層次上其實是上層系統程式與下層使用元件的關聯。

2007年8月8日 星期三

C27 設計元件的放置架構記錄

即使是在同一個Use Case裡,在不同的Tier裡都至少會經由一個以上的Service來控制當時系統應有的動作。在我的設計裡,Component是只能被Service所呼叫的元件,所以在設計Service物件的同時要記錄在哪一個Tier各使用了哪些Component。

記錄的意義同樣在分析關聯,我們可以看出Component被哪些Use Case的哪一段Service所使用。從Tier的觀點來看,每一個Tier都知道總共使用了哪些Component,同時我們知道每個Component各屬於哪一個library,收集起來並加上系統本身在那個Tier應有的程式,得到的就是在那部電腦上需要額外安裝的檔案。

在這個時候,應該產出一張表格註明每一部硬體的規格,使用的作業系統,安裝的應用程式,使用的Component Library與系統預計產出的程式。未來安裝各部分的硬體時,就依照這個表格來製作安裝手冊並安裝之;日後有人問任何硬體所需要的規格與軟體時就可以立即提供。

不過還是要記得,有任何的變更時,這份文件也是必須要同步更新才能隨時得到最正確的內容。




◎系統的目標

2007年8月7日 星期二

C26 Activity Diagram設計產出(2)──Class Diagram

每個Use Case Realization裡也該有Class Diagram,在Sequence Diagram裡為Interface與Class拉上關聯的同時,也該把那個Interface與Class放進這張圖裡。從Class Diagram裡我們可以很快地得知每個Use Case使用的所有Interface、Class與彼此間的關聯。

如果可能的話,努力將每一個Tier(每個Tier對應到一部電腦)裡所用到的類別都作成一張Class Diagram以顯示其架構,同時把Interface、Class之間的繼承與使用關係都放置在圖表裡。

此時的Class Diagram是一部電腦裡必須要有的所有元件介面,在所有Interface都已經定義、實作Class設計好大概並決定好所屬的Package後(方法還可以增減或變更,元件名稱與位置若有增減或改變就得相對地修正),接下來還要考慮哪些意義相似的Package要被包裹成一包library。切分library的基本想法留待C27再作說明。

以靜態的角度來看,最小的單位是Interface與實作的Class,這個物件可在Class裡描述其繼承關係、說明與所屬的所有方法,如果是Service層級者則拉出一張圖來表示它所有的關聯;Interface與Class在建立時就放置在其所屬的Package裡。再往上的單位是Package,由於Rose Model裡可以取得Package裡所有的物件,所以可由SoDA產生Package裡的物件清單而不見要有圖;設計時如果把Package的範圍等同於Component的範圍就可以省卻一張圖。

要有哪些Class Diagram除了決定什麼情況下該有之外,同時也根據什麼地方需要特別說明就多加一張圖註明。

[這裡應該有一張Class Diagram]

2007年8月6日 星期一

C25 Activity Diagram設計產出(1)──Sequence Diagram

在Use Case Realization裡首先要做的是根據Activity Diagram從功能的開始,逐步敲定每個步驟如何在系統裡實作:判斷是否可以進入功能的處理、處理時一層層地決定現在到達的層次、在該層次裡由哪些元件做事、經由哪些元件的方法、應該傳遞些什麼等等。這些Use Case Realization的想法記錄在UML裡,是靜態的Class Diagram與動態的Sequence Diagram。

對於每個Use Case Realization首先要建立屬於它的Sequence Diagram,根據Activity Diagram裡的Activity,逐步在這兩張圖表加上應有的元素。設計一個動作時都有同樣的三件事情要做:決定由哪個元件來做(Component Name)、決定由元件的哪個方法做(Component Method)、決定做的同時要傳入什麼與傳回什麼(Method Parameters & Return Objects)。

如果找得到已經存在的元件與方法可以使用,只要將元件放進Sequence Diagram並拉上呼叫的方法關聯。如果沒有可使用的則必須依照所需的呼叫方法,看是要新增一個功能元件並加上對應方法,或是挑選一個已存在的功能元件只加上對應方法,新增之後再把元件放入並拉上關聯。

以上的設計依據之前分層的方式都定義在元件所屬的Interface上,同時為了方便日後的追溯最好在元件與方法的註解都註明是哪個Use Case所使用的。使用以上的原則,為Use Case裡所有的劇本建立起Sequence Diagram;依此類推直到所有Use Case Realization都處理完成。

[應該有一張 Sequence Diagram]

2007年8月5日 星期日

C24 理論串接實作的瓶頸(6)──Properties, Message, Log

在設計系統的時候,有幾個項目是貫穿全部功能都需要的,像是訊息、記錄以及參數等等。這些項目如果在設計的時候沒有周全的考慮,同樣會有使用時機與層次不一致的影響。

Message:在功能處理的流程裡,處理的經過與結果在必要的時機都需要回饋讓使用者知道。需要設計的有顯示訊息的機制與訊息對照表。系統可以設計一個自己專用的訊息機制,在設計的時最好以提供給其他系統使用為基準,作出通用的元件。

Log:使用時機與設計方式都與訊息雷同,是在處理經過中記錄下系統的必要內容。通常出現的時機與訊息差不多;訊息是該時間點讓使用者知道系統處在什麼狀況下與可以作什麼動作,記錄則是讓使用者能夠查詢在那個狀況下,系統內部的狀態如何,必要時可以追蹤問題的發生原因。

Properties:參數的設定應由系統統一管理,在初始化或是即將進入該段處理的時候使用參數決定處理的方式。常看到的設計是元件裡自行讀取自己用的參數檔案,以元件的立場來看封裝參數是可以理解的;但從系統的角度上來看過多的設定會讓系統的設定失去一致性。所以我會將參數的管理放在系統層級,控制元件的參數再使用Properties物件傳入。

開發系統的極致,是讓未來的開發或維護,在沒有改變設計邏輯情況下只要更改外部檔案的定義就能產生執行參數的效果,不需要再更動任何程式。通用設定如果存在於一致的層級,編輯與維護都會比較容易;更理想的是在提供的參數夠多讓系統更趨於成熟時,就可以提供外部參數檔的編輯器,甚至設計SA Tool之類的產品,在訪談時所作的記錄可以自動產生基本的框架與設計以節省大量重覆開發的時間。

2007年8月4日 星期六

C23 做事的方法(6)──察言觀色、見機行事

小朋友們與爸爸開心地互相逗弄著,家裡充滿了歡樂的笑聲;忽然間電話響了,老板打來跟爸爸說明天到公司辦資遣手續。掛掉電話後,小朋友繼續想跟爸爸玩,結果被爸爸大罵一頓,結束了快樂的時光。

小朋友們做的動作是前後一致的,為什麼會得到不同的反應?很明顯地是因為有一通電話對爸爸傳遞指令造成了改變,因而使他的心情變化進而對同樣的事件有不同的對待。小朋友像使用者,進行同樣的操作動作;電話就像是參數的改變,讓爸爸像系統的處理般與之前有所差異。

在生活裡有兩個方向可以考慮:當別人的反應模式改變時自己該如何面對,與如何利用方法來改變一個人的行為。古人訓示裡的察言觀色與見機行事是教我們如何觀察他人的改變並因應行動;某個功能本來可以印表的,但剛剛有人暫時把印表機拔走,如果此時使用者還是硬逼成系統要列印,那麼這個使用者通常會被歸類為“白目”型。

當希望讓某人做出自己期望中的改變時,我們會設計讓那人照我們的想法去做,古代流傳的說客故事呈現的是這個事實。若期望在某個功能裡可以依照特別的想法去改變處理流程時,我們可以安排參數的存在來造成這樣的影響。

見機行事,機可以是既成事實的反應動作,也可以是我們期望要發生的反應。無論如何,只要有變化存在就必須投入相對的努力與資源總是不爭的事實。

2007年8月3日 星期五

C22 Model的設計(1)──Model的存取


這張圖是我所認定整個系統具有的完整層次。Model的部分是以淡紫色所顯示的部分。

為了支援各種不同的Model實作,首先要定義的是Model的存取介面,這個介面定義的是Model自身內部資料的存取方式與邏輯;再上一層會有Model Service,裡面定義了跨Model存取邏輯的封裝。

如果有個戶政機關想統計轄區裡所有人的平均年齡,那麼會在代表人的Model裡定義取得年齡的方法,交由上一層的Controller計算平均年齡;如果戶政機關想統計的是所有家庭夫妻差距的歲數,這時就得在Service定義一個方法,分開從Model各取得的夫與妻的年齡再傳回差距的歲數。

縱觀View Service、Controller Service與Model Service,其實我們可以發現功能分析時確定要做的每一步驟都會在這幾個層次裡設計,在設計的同時必須確定每一個動作要如何實作,是否要使用元件。在我的想法裡,Service裡應放著系統的處理邏輯,每個動作都該放進元件裡實作(很簡單的動作則另外拉個API),如此可以明確分隔出二者的意義;此時每個使用到的元件介面就必須在架構設計階段內同時設計與定義。

在這個設計步驟完成時,整個系統的功能設計就告一段落;每一個功能、每一個步驟、每一個動作的處理邏輯都應該包含在內。至於如何達成處理動作,就交由元件來完成。

2007年8月2日 星期四

C21 做人的方法(5)──人正是Controller

環顧辦公室的四周,你會發現能夠依著自己意志取用物品的只有人類而已(帶寵物上班的地方除外);辦公室的環境能否維持整齊清潔,其實也就跟人類息息相關。

對應到系統來看,辦公室裡的物品可以視為資料,而人類就是可以隨意控制物品取放與移動的Controller,人能夠隨意地改變物品的所在位置。如果沒有規範,物品會在被使用後被丟到一個可能永遠找不到的地方;再過段時間後,等到不在位置上的物品且不該在位置上的垃圾一多,辦公室就顯得髒亂。

具有“從哪裡拿到的就放回那裡,不該放在那裡的物品不會放”這種美德的人實在不多,很多的人只為了貪圖自己的方便,以最快的方式取得要用的物品,使用後就隨手一放就走了,接下來的人就深受其害。常有人嘆息管理不易,但用另一個方向思考,只要每個人都做好自己應做的事情,放好該放的東西,整個團隊不就已經完全正常運作了嗎?

我們要記得自己是唯一控制經手物品的Controller,必須在對的時間用正確的動作取得該用的資源,並在使用之後立即將之回歸到原來的地方或該去的地方。如果沒把自己經手的物品回歸到它應該放置的地方,不是另一個人要付出代價讓它歸位就是環境要承受它不在位子上帶來的問題。遇到事情時思考施與受雙方面,牢記不要為他人或大環境帶來麻煩,常懷有這樣的想法後就會自然而然地把經手的所有事物作最佳的安置。

請記得對人而言,經手的資源除了物品外,還有自己應記得的一切與該去做的的一切;也就是說要妥善安排與自己相關的所有人、事、時、地、物。

2007年8月1日 星期三

C20 理論串接實作的瓶頸(5)──Controller≠Component

Controller是系統的靈魂,意即是最重要的部分,但是在許多介紹OOAD技術的網頁裡,Controller就直接被定義成一個Component。這樣的作法,讓我頭痛地摸索很長的一陣子都找不到出口。直到參考了幾篇提到Business Logic與Function Logic應分開設計的網頁後,才終於明白應該要有的理想層次。

先以一個例子來說,我們的系統需要在幾種不同的印表機上列印結果,我們的系統有一套產生列印內容的處理,另外要有驅動印表機的機制。在最初的需求裡只支援一款印表機,所以當時的設計定義一個Interface,再把列印內容的處理與驅動印表機機制寫成直接使用類別(相當於視作一個Component)。

後來因其他專案的需求,必須支援其他兩款印表機。最快的作法就是把原來的類別再複製一組,再修改差異的地方,但是這樣雖然快卻會在系統裡出現數組幾乎相同的程式碼,除了造成維護的負擔也顯示出設計上的問題──幾乎沒有設計而只有實作。

後來還是決議把處理內容的邏輯與印表機控制拆開,在中間插入一個控制印表機用的Interface;這樣就成為三組印表機功能實作對應三款印表機,但是內容處理的部分就只要一組。處理內容屬於Business Logic必須在架構設計時處理,印表機功能屬於Function Logic(因為每種印表機的控制都有差異)是Component細部設計的範圍。這樣的作法才完全符合我的架構設計理念。

省卻設計的層次雖然能夠節省初次開發的時間,但也僅只於此一利,之後的任何結構上的需求變更都將會凸顯其害。

2007年7月31日 星期二

C19 Controller的設計(1)──Business Logic


這張圖是我所認定整個系統具有的完整層次。Controller的部分是以淡藍色所顯示的部分。

在Controller裡所要設計的是輸入結束後的系統處理,通稱為Business Logic的部分。第一個進入的Controller是對應Use Case的Activity Diagram的控制物件,本身只負責流程該換到哪個Activity執行而不要有任何其他的實作摻雜在裡頭。

第二層的Activity Controller裡是Activity應有的邏輯控制,在設計的時候同樣先用文字簡單表達處理的步驟,每一個小步驟都對應到一個Controller Service裡的方法。同樣地這裡純粹是控制,不要有其他的處理。有些系統的開發會把這兩層的控制包裝成Operation Flow與Operation Step的交易流程套件來減少額外的開發。

實作的功能都放在Controller Service這一層裡。比對View Service來看,我們可以發現Service才是系統真正放置功能的地方,唯有在這裡才允許存取或操作到不同層級的物件。在Service裡都是處理動作的實作,每個動作的設計都必須決定是要使用現有的Component、自己設計新的適用Component或是自己寫程式在方法裡處理。(這裡的Component必須與Business Logic無關)在確認Service動作的同時也必須要設計或定義使用Component的介面。

驅動程式各部件運作的關鍵層次,就是Service;經由這裡存取Model與View,並達成與外部的連接,一切功能需求裡提到的系統互動動作,大多會在這個層次實現。

2007年7月30日 星期一

C18 View的設計(3)──進入Controller

這層設計的一開始,要先決定View進入Controller的對應事件與傳遞的物件。在一開始的基礎關係,每個功能會有自己的View,自己的Controller,如果不去抽取相同的部分就會得到前面提到的大學生程式類型,造成每個功能都有一大堆重覆的程式碼。我們可以在View與Controller之間使用Façade Design Pattern作為唯一入口,在執行事件的Service裡把View的欄位與值在listener包裝成適當Model傳入Controller。

以Façade類別作為分界點,無論使用哪一種GUI元件開發顯示畫面,只要在進入執行時傳入指定的Model,後面的Controller都可以正常地處理;反過來看,只要Controller都符合傳入Model的介面,把畫面的Listener組成該Controller所需的Model就可以呼叫它。這便是用來應付可能發生的變化的設計應對。

許多經驗較少的人把交易的邏輯寫在顯示的類別裡,在處理資料的時候直接對顯示物件操作。由於指定物件本身的類別名稱,就會造成處理與顯示之間的密合而無法隨意更換,這樣的設計就像是一體成型的機器人手臂;因此我們需要在意義不同的層次上加工製作隔開兩邊的介面物件,藉此來達到可以抽換另一端實際執行物件的活動機制。

2007年7月29日 星期日

C17 做人的方法(4)──人會是Listener

在忙碌的工作裡,我們需要安排自己的工作項目與時間分配。手邊有哪些工作,每個工作的開始日與完成日都要牢記;還要記得所有會議的時間與地點,會議中進行哪些討論,要先準備哪些物品。在工作安排初期與會議敲定的瞬間,心裡都知道有那些事的存在,但是時間點到的時候能保證全部都記得嗎?

任何事都可能會忘記,一旦忘記沒做好接下來可能有重大的影響,許多人會用筆記本記錄未來要處理的所有項目,每天不斷地檢查清單的內容看有哪些項目是現在要做的。這像是使用polling的呼叫模式,每隔一段時間就必須記得去檢查,有狀態的改變時就去處理;但也會有一些時候檢查了也沒有要做的事浪費檢查的時間,或是在該去檢查的時間點沒去檢查而錯過時機。

我喜歡用PDA記錄工作項目與行事曆。該在什麼時間準備什麼樣的資料與做什麼事,全都記錄在行事曆中並設定鬧鐘提醒,時間點一到PDA就會自動提醒該做事項的內容。平常要記的事情已經夠多了,再加上這類瑣碎的事情實在會煩死人;使用行事曆後就能放空這些小事來專心工作,等到PDA提醒該做事的時候,再參照工作項目的內容去處理要做的事實在是輕鬆多了。

面對雜事的時候可以只是單純的Listener等候通知,但是處理工作事務的時候就不能被動成這個樣子。老板們總希望每位員工都是運作良好的Controller,能夠把手邊所有的工作項目理想地安排並完全地掌握所有事項的進度與狀況;這也是每個人都應該做到的基本能力。

2007年7月28日 星期六

C16 View的設計(2)──事件與處理

畫面在顯示之後就等待使用者的輸入與操作。所有程式語言工具對於畫面操作事件都有詳細的規畫與定義,所以大家對Listener介面的使用都很熟悉。這裡想要討論的是Listener的實作與事件對應處理邏輯的關係。

由於操作事件會跟隨著畫面作反應,所以把Listener的實作放在畫面呈現的類別裡是直覺的設計想法。我們發現有時同樣的事件與處理大量地重覆出現在很多畫面(例如系統規定Enter鍵是執行功能的熱鍵),在這樣的情形下相信所有的人會把Listener拉出到一個專門的Class來處理同樣的事件。

現在在這裡最常遇到的問題,是在拉出Listener後仍然把事件發生的對應處理寫在Listener裡面,造成難以切割的密合狀態。這時只要事件與處理邏輯之間的對應關係有所改變,都必須搬動整段程式碼才能達成;就算把這些處理提出到獨立的方法已經有做抽取動作,但也不算是正解。因為,無論如何都會動到程式碼。

如果認真“回憶”的話,我們在需求階段製作的Activity Diagram有分User與System的Swimlane,從User指向System的線條就是event,進去後系統的連鎖Activity正是系統要對應處理邏輯。我們要注意的是,反應由一堆Activity依序組成,每個Activity對應到一個ViewActivity物件的話,管理執行順序的工作交由一個ViewFlow物件處理,Activity的處理內容再交由View Service處理。

右上角的藍色框就是對應每一個event所應該設計的反應機制,當需要再往後執行功能邏輯時,會再往後面的層次傳遞。


2007年7月27日 星期五

C15 做人的方法(3)──把用過的資源放到該放的地方

宣告記憶體佔用,並在使用後釋放乾淨,這種維持系統運作正常的原則,同樣也是人類在日常生活中對於環境應該遵守的準則。

要記得我們多做了不該做的或少做了應該做的事時,周遭的人事物必定會受到相對的影響。例如拿出來用的物品在使用後要放回原處,這樣所有人才能照SOP規定的步驟在該拿到物品的地方取得,今天我們拿了物品不放回去,必然會造成應該取得物品的動作拿不到,同時不該有那項物品的地方多了這件物品。這便是相對的影響。

現在常看到很多人在路上隨手丟煙蒂、紙屑,丟棄後還能夠輕鬆自在地離去,從環境的角度上來看那個地方就多了一項破壞景觀的物品;隨處丟棄不想養的寵物也是這樣,把自己應該處理的事推託給別人或是大環境裡,個人所減少的負擔就這麼加重在其他人的身上。把物品在正確的時間點放到它該存在的地方,同樣是我教育小孩的信條。

每個元件如同個人一般把自己經手過的物件歸回到處理前的狀況,那個系統就會如同大環境一樣得以長久地良好存在。裡頭有任何一個元件沒有做好,就會有相對的小小影響;現在的硬體等級都很好,也許要經過很久才會出現問題,但因資源取得容易就認為可以隨便取用且亂丟終究是錯誤的行為。

保證每個元件處理好經手的資源,是維持系統穩定的必要條件;同樣地,人對於地球也應該抱持同樣的想法,才能讓生存的環境維持機能。至少,立即隨手把自己取用的物品放回原處,可以讓自己居住的場所保持整齊清潔,帶給身在其中的人較好的心情。

2007年7月26日 星期四

C14 View的設計(1)──起始與結束


這張圖是我所認定整個系統具有的完整層次。View的部分是以淡綠色所顯示的部分。

在架構設計的時期,第一步設計的對象是架構好上方所有的Interface,接著就思考每個部分的實作與對應使用的Component Interface,Component的實作則會在細部設計階段才需要處理。在這個階段,設計者應決定每一層Interface所應存放的位置,同時決定每一個功能在每一個Interface裡所對應的方法,以及方法裡應該作出的反應。

首先,在起動系統或是準備功能執行狀態的時候會有一個起動功能Controller負責產生顯示給使用者操作的畫面。畫面大多會以GUI(Graphic User Interface)呈現,裡頭必須包含功能所需之資料對應欄位(有些資料是經由計算或另外擷取的)。絕大多數的View只會有一種,這時可以省略掉Interface的定義;但是如果系統打算採用Multi-Channel的設計,就必須定義介面提供更換不同種類的View來存取畫面上的資料。

設計任何一個層次的時候,除了起動時自身的生成,同時也要注意功能完成後擁有物件的釋放。重覆不斷地使用資源卻沒有完全釋放的功能,會造成硬體的Memory Leakage而逐漸佔用系統記憶體,終至記憶體不足以宣告生成物件而導致系統停擺。在網路上所搜尋到的教學網頁全部都是教大家如何使用物件,還沒看到過同時教大家如何正確地完全釋放物件。結束時釋放的原則是以生成的方法順序倒過來逐一實行。

2007年7月25日 星期三

C13 小小的改變,大大的費時

公司的系統需要使用其他廠商的硬體來擴充功能,因而要我設計一個元件來對應這些功能。需求是在畫面上操作某些動作時,把資料變成XML字串送給其他系統,回應的結果再顯示到畫面上。

一開始沒想太多,只把送出的XML作成Model物件,Controller裡就直接在需要顯示的地方使用View的物件(公司的View經過包裝,使用自行開發的API),只用了幾天的時間很快地把功能做好並測試完成。過了幾天,主管說這個元件希望可以單獨銷售使用,View的部分希望可以同時支援標準的swing,為了做出這個功能我花了四個小時把Controller裡的View拆出並定義Interface。

直接把Controller與View分開並定義介面所花的時間應該只比原先直接使用的設計多一個小時,但是我花了整整四個小時做這個動作。而且在拆解的過程裡程式碼大量地被分割,連帶地所有功能全部要再重測與修正,總共用了六個小時左右,實在是得不償失。

類似的經驗在維護列印的元件上。當初寫這個功能的人看需求只要使用一款印表機,所以在列印的邏輯裡直接使用印表機物件;現在因專案的緣故必須支援三款不同的印表機,為了重覆使用印表邏輯,我必須花很大的功夫拆出邏輯與印表機功能物件並在其中定義介面。當然拆解後重新測試元件全部功能的動作還是免不了的。

當你多遇上幾次這種重拆重測的事,浪費許多時間重做之後,如果你是那個負責拆解與維護的人,相信你會更明白為每一個層次定義介面的重要性。

2007年7月24日 星期二

C12 應付變化的設計──Design Patterns

系統設計時常有需要變化的地方,累積了多次的開發經驗後,有人統計分析出一些較常見且需要的變化,並且設計出解決對應問題的機制,這些機制被稱為Design Patterns。

Design Patterns是很熱門的話題,搜尋一下網路可以找到許多相關的網頁。Design Patterns集結了前人的智慧解決系統設計上常見的需求,讓系統更具有抽換元件的彈性,但是增加彈性的代價是使用更多的Class來達成功能。因此也有Anti-Pattern的聲浪出現,希望設計時不要動不動就套用Design Patterns而造成設計上的負擔。

在應該變化的地方才使用Design Patterns是目前較中肯的使用時機,分析使用者所有需求的內容來決定哪些地方該使用Design Patterns。這樣的想法是合理的,如同記錄的內容需要平衡,設計的內容也同樣需要平衡;但是需求都可能變更,沒有人知道現在確定不變的事在未來會不會永遠不變。

我所採用的設計原則是:確定會變的地方套用Design Pattern,有可能會變但現在不變的地方定義Interface而不使用Class。設計時定義Interface再實作所花的時間大約是直接使用Class的三倍,但是把已經寫好的直接使用Class原件拆出Interface與實作差不多要花直接使用Class的九倍時間,而且還要另外再加上重新測試的時間。

就像記錄應該記下所有的事,但是內容應該簡單不要花太多時間,在設計的時候也應該為所有應該切割的地方定義介面預留未來的改變,但是不需要全部都套用Design Pattern。

2007年7月23日 星期一

C11 小朋友的親屬稱謂表

低年級的小朋友前陣子在苦背親屬稱謂表,一大堆叔、伯、姑、嫂、公、婆之類的名稱一下就讓小朋友頭昏腦脹,更何況還得去記得“爸爸的爸爸是爺爺“,”媽媽的姐姐是阿姨“等等這樣的人物關係。

教了幾種關係後,發現小朋友已經無法再多記,同時也感覺這樣的記法實在太耗費腦力;轉念一想,這個問題好像可以用OO的理念來解決耶。“人”肯定是獨立的個體,“稱謂”不正是從自己看出去後人與人之間關係總計後的結果嗎?只要定義好“人”這個類別,同時適當地決定與其他“人的關聯,那麼從關係求得”稱謂“是順理成章的。

“人”都有一位父親與一位母親(在這裡不討論例外情形)的長輩關係,同時有兄、弟、姐、妹四種同輩集合、子與女兩種晚輩集合、以及一位配偶關係。接下來從自己開始擺好課本所教的層數再拉上與人的對應關係,往長輩一層叫“父母層”、兩層是“公婆層”;父親的兄弟姐妹層的展開是伯、叔與姑姑,他們的配偶稱為伯母、叔母與姑丈;母親的兄弟姐妹層展開是舅與姨,他們的配偶稱為舅母與姨丈,依此類推……。

原先只能硬背的親屬關係在適當地切割獨立元件後,成為有條理可依循的關係圖表,相形之下學習者的可接受度與理解能力大幅地提升了。明明是相同的東西,經過設計與規畫再加以適量的說明,就可以把整個觀念傳遞給原先不清楚的人,這也是我們應該努力達成的方向。