第八章 分析與設計階段 – 物件導向設計(OOD) 軟體工程 -物件導向程式設計與UML系統分析實作 By 林錦陽 (Chin-Yang Lin) 2004/9/22
綱要 前言 類別的規劃 物件導向設計階段 (OOD) 建立動態模型 建立設計模型 總結
前言 OOD目標: 手段: 將OOA階段的分析模型,繼續透過反覆的修正與演進,使得整個模型能更趨於完備。(即:足以拿來實作之完整類別模型) 以圖7-4為藍圖,繼續以各種基於好的物件導向設計原則進行檢視。
物件導向之分析設計程序 (圖7-4)
主要任務 建構互動圖(Interaction Diagram) 建構狀態圖(Statechart Diagram) 建構詳細的類別模型(Detailed Class Diagram) 撰寫虛擬程式碼(Pseudo-Code)
在這之前…類別的規劃 問題: 人機介面(Human Interface): 在OOA階段,「使用者與系統的互動媒介」似乎並不明顯? ATM(自動提款機)的輸入裝置 圖形使用者介面(Graphical User Interfaces)
範例探討(1) 一般商務系統至少具備了… 核心類別:”訂單” 功能:顯示訂單明細 假設以GUI為人機介面
(Cont.) 就物件設計的角度來看,顯示訂單明細的功能由”訂單”物件自己來負責,似乎是理所當然!不過… 考慮以下的狀況: 若系統中存在上百個有需要跟使用者直接做輸入輸出的類別,一旦使用者與系統互動的介面需求有所變更時,套用此設計方法將有何影響? Note: 介面需求變更常發生在文字模式(Console-based Mode)與視窗模式(Window-based Mode)之間的轉換,或是更換不同的視窗工具組/函示庫(Windows Toolkit/ Library)。
(Cont.) 主要影響: 問題根源: 此時會有很多的類別需要跟著修改(如:上例中的”訂單”) 。 核心類別與使用者介面之間的過度耦合 (核心類別被使用者介面綁住了!)
典型解法 隔離核心類別與使用者介面 邊界類別(Boundary Class) 實體類別(Entity Class) 注意圖中的相依關係 專司使用者介面 實體類別(Entity Class) 即核心類別 (通常為永續物件(Persistent Object)) 注意圖中的相依關係 理論上,核心類別對邊界類別一無所悉。
(Cont.) 變更訂單介面等邊界類別(如:Form/Frame、Edit、 Button),並不用跟著修改”訂單”類別。
範例探討(2) 基於上例,考慮另一個需求: 假設透過邊界類別需要完成的是 - ”替某顧客建立訂單的程序” 可能之類別結構以及物件合作關係如下…
(Cont.) 部分流程控制的工作將落到邊界類別 考慮同樣的狀況:當使用者介面需求有所變更時… 邊界類別需協調多個實體類別(如”顧客”、”訂單”以及”訂購明細”)來完成登錄程序。 考慮同樣的狀況:當使用者介面需求有所變更時… 儘管實體類別不需修改,但邊界類別中的部分商務邏輯(控制流程)卻還是得重新撰寫!
再次隔離… 在實體類別與邊界類別間加上控制類別(Control Class) 由控制類別包辦商務邏輯相關的控制流程
(Cont.) 此時邊界物件便不需涉及特定之控制流程,就算邊界物件有所變更時,嵌在控制物件中的控制流程仍可被保留下來。 此外,許多錯誤處理的相關動作,也可由控制物件集中處理,不需分散在邊界物件中。
小結 對類別作如此細膩的切割動作固然需要不少時間成本,但將有利於系統日後的擴充與維護。 依照類別(物件)的性質可區分成: 邊界類別(Boundary Class): 負責使用者介面 實體類別(Entity Class): 負責問題領域的核心資料 控制類別(Control Class): 負責邊界物件與實體物件的協調(流程控制)
(Cont.) 其他應用: 資料庫存取 (更換不同的資料庫系統也是很常見的事情) Note:此概念源自於MVC (Model-View-Controller) Pattern。
物件導向設計階段 (OOD) 主要執行步驟,細分如下: 加入邊界類別與控制類別 建構互動圖(Interaction Diagram) 建構狀態圖(Statechart Diagram) 建構詳細的類別模型(Detailed Class Diagram) 決定類別行為(Operation) 加入設計階段的類別 決定可見度(Visibility) 決定資料型態 撰寫虛擬程式碼(Pseudo-Code)
Case-Study: 加入邊界類別與控制類別 考量是否需要控制類別 被協調的兩端在性質上是否有明顯分野 例如:邊界類別與實體類別之間 被協調的兩端是否有需求變更之虞 例如:軟體元件或(類別)函示庫 通常… 使用者(Actor)與Use Case之間,會是置入控制類別的適當位置
以訂房程序為例 訂房邊界類別 資料庫控制類別 泛指所有相關的視窗元件 (為簡化起見) 專司資料庫存取動作 降低實體類別與資料庫介面之間的耦合性
(Cont.) Note: “訂房控制類別”與”資料庫控制類別”均有機會指涉到許多實體類別,這跟實際運作的流程有關,在此暫時省略這些關係。
Case-Study:建構互動圖 參考來源 類別圖(模型) 取得物件(類別)互動時的主角 Use-Case腳本 取得物件的互動流程
(Cont.) 是否物件間所有的互動都要畫出? 畫出的互動情形越多,將有利於決定詳細類別模型時的精確度。 基本要求: 其他考量因素: 至少要描繪出每個Use Case腳本的主要流程 原則上夠用就好! 其他考量因素: 時間、成本、軟體系統種類以及是否有透過輔助工具(CASE Tools)…等
(Cont.) 互動圖要詳細到什麼程度? 基本原則 - ”盡量保持簡單” 把複雜的互動情況拆解成多張互動圖
基本流程-順序圖
基本流程-合作圖
由基本流程(Basic Flow)可知,此時已確定該房間在該時間範圍內為空房。當”資料庫控制類別”要取回時間範圍物件時,如果發現該物件不存在資料庫中,便會自動新增一個時間範圍物件於資料庫,之後再進行回傳。 訂房操作細節-順序圖
訂房操作細節-合作圖
Case-Study:建構狀態圖 狀態圖只針對單一物件來描述 狀態圖非絕對必要: 除非… ”某類別的行為與狀態有相當程度的關連性” 例如:”電話連線類別”,該類別”撥電話”、”掛電話”等基本行為都跟電話的狀態有關(如:連線狀態、響鈴狀態) 。
資料庫控制類別 - 狀態圖
Case-Study:建構詳細的類別模型 決定類別行為 加入設計階段的類別 決定可見度(Visibility) 決定資料型態
決定類別行為 責任導向設計(Responsibility-Driven Design) 訊息接收端(服務端)負責提供該訊息的服務
(Cont.) 互動圖提供了大部分的訊息資訊 通常直接把互動圖中的訊息當成類別行為 互動圖愈精密,捕捉到的類別行為也就愈多
訂房程序相關類別圖(1)
(Cont.) 資訊隱藏(Information Hiding) 保護物件內部資料(屬性) 為資料提供公開的存取介面(方法) Java/C++之private修飾子 為資料提供公開的存取介面(方法) Java/C++之public修飾子 例如:訂房資訊類別(訂房程序相關類別圖(1))中的訂房日期應該受到保護,並提供一組存取方法,分別是”設定訂房日期”以及”取出訂房日期” 。
(Cont.) 基於“資訊隱藏”的概念,可再次捕捉到許多行為! 如下圖-訂房程序相關類別圖(2) Note:訂房程序相關類別圖(2)中,只列出部分屬性對應的方法。
訂房程序相關類別圖(2)
加入設計階段的類別 設計階段的容器類別 例如: 如:Array、List、Vector... 必須在OOD階段被考慮進來
(Cont.) 對於這類的結構,在此一律以List來表示 List所包含的資料項目通常是物件參考或識別碼 加入容器類別
(Cont.) 考慮應用程式的起始點: 在此補上一邊界類別-”訂房系統應用程式”,該類別為應用程式的起始點 以Java而言,此類別中包含了main方法
加入系統起始類別
(Cont.) 考慮多重性(Multiplicity) 例如:”顧客”可以有多筆”訂房資訊”,而每筆”訂房資訊”則只歸屬於一個”顧客”。此時通常讓顧客保有一份”訂房資訊清單”,而訂房資訊則保有可參考到顧客的屬性 。
決定可見度(Visibility) 軟體組成(單元): 某個軟體組成之可見度,決定了該軟體組成是否可被其他軟體組成所存取。 屬性、行為、類別、套件…等 某個軟體組成之可見度,決定了該軟體組成是否可被其他軟體組成所存取。
常見的可見度分類(以Java為例) private public protected friendly/package 只能被相同套件中的其他成員存取
公開(public)等級以’+’來表示,’-’則為私有(private)等級 加入可見度後的類別圖
決定資料型態 目的: 決定屬性資料型態 決定行為的原型定義 (Note:若屬性具有初始值,此時可一併設定) 例如:整數(integer)、字串(String) 決定行為的原型定義 傳入的參數列(Parameter List)以及回傳值型態 (Note:若屬性具有初始值,此時可一併設定)
加入資料型態後的類別圖
撰寫虛擬程式碼 目的:讓後續的實作更有所依據 通常只挑選具代表性的或是比較複雜的程序來撰寫。 撰寫語言: 自然語言 程式描述語言(Program Description Language) (Note:應避免直接用特定的程式語言)
類別名稱:訂房控制類別 方法(操作):訂房 輸入:name:String, id:String, roomNumber:Integer, startDate:Date, endDate:Date 輸出:None (Void) 功能描述:完成單筆訂房資訊登錄的動作,而相關的資訊會反應到資料庫中。 void order (name:String, id:String, roomNumber:Integer, startDate:Date, endDate:Date) { 房間 room = 資料庫控制類別.取回房間(roomNumber); 時間範圍 timeInterval = 資料庫控制類別.取回時間範圍(roomNumber, startDate, endDate); room.加入時間範圍(timeInterval); timeInterval.設定狀態(訂房狀態); //訂房狀態的型態為Integer 顧客 customer =資料庫控制類別.取回顧客(name, id); if (customer exists) //not null 訂房資訊 orderInfo = new 訂房資訊(); orderInfo.加入房間(room); customer.加入訂房資訊(orderInfo); 資料庫控制類別.完成預定(customer, orderInfo); } else //進入顧客建檔程序 (略)
總結 本章簡單呈現了OOD時期常見的工作,從類別的規劃、動態模型的建構(互動圖、狀態圖)、詳細類別模型(設計模型)的成形,到虛擬程式碼的撰寫…等。 Note:使用者介面以及資料庫的相關塑模技巧屬於專門技術,而且通常跟特定的函式庫或系統介面相關,並不在本課程涵蓋範圍內。
(Cont.) 最後要再重複強調的是: 不管分析或設計,免不了重覆往返的過程。 適度的往返修改,是軟體發展過程中的常態(尤其是針對中大型的軟體系統) 如何讓往返修改的錯誤與負擔達到最低,這跟個人經驗有關,同時也是學方法(論)的目的。
The End