標籤:其他 思想 物件導向設計 分解 通用 本質 img 軟體開發 選擇
結構化方法與物件導向方法的概念都存在已久,但它們至今仍是活躍在一線、影響力極深的軟體工程開發方法。結構化方法的核心是模組化思想與自頂向下的設計思想,它將一個複雜的問題進行分解,從而將其拆分為幾個規模較小的問題,之後按照同樣的方式對於分解後的問題進行進一步拆分,直到某一步中問題已經相對較為獨立;而物件導向方法則是將構成問題的事務分解為各個對象,與之前不同的是,每個對象設計的目的不是解決某個問題,而是為了描述某個事物在解決問題的過程中的行為。本文將首先對於兩種方法都進行較為詳細的介紹,之後結合執行個體對兩種方法的優缺點進行比較。
結構化方法
結構化方法包括結構化分析(SA),結構化設計(SD),結構化程式設計(SP)三方面內容,分別對應於軟體開發中的分析、設計與編碼階段。
結構化分析
結構化分析方法(Structured Method)是強調開發方法的結構合理性以及所開發軟體的結構合理性的軟體開發方法,它給出一組協助系統分析人員產生功能規約的原理與技術。它一般利用圖形表達使用者需求,使用的手段主要有一下四種。
1、資料流圖(DFD-Data Flow Diagram)
資料流圖是描述資料處理過程的工具,是需求理解的邏輯模型的圖形表示,它直接支援系統的功能建模。
資料流圖中主要圖形元素有:
→:資料流—流是資料在系統內傳播的路徑,因此由一組成分固定的資料群組成。如訂票單由旅客姓名、年齡、單位、社會安全號碼、日期、目的地等資料項目組成。由於資料流是流動中的資料,所以必須有流向,除了與資料存放區之間的資料流不用命名外,資料流應該用名詞或名詞短語命名。
□:資料來源(終點)—代表系統之外的實體,可以是人、物或其他軟體系統。
○:對資料的加工(處理)—加工是對資料進行處理的單元,它接收一定的資料輸入,對其進行處理,併產生輸出。
〓:資料存放區—表示資訊的靜態儲存,可以代表檔案、檔案的一部分、資料庫的元素等。
建立資料流圖步驟如下:
(1)由外向內:先畫系統的輸入和輸出,然後畫系統的內部
(2)自頂向下:順序完成頂層、中介層、底層資料流圖
(3)逐層分解
2、資料字典(DD-Data Dictionary)
資料字典是結構化分析方法的核心。資料字典是對所有與系統相關的資料元素的一個有組織的列表,以及精確嚴格的定義,使使用者和系統分析員對輸入、輸出、儲存和中間結果有共同的理解。
資料字典的作用是對資料流圖(DFD)中出現的被命名的圖形元素的確切解釋,通常資料詞典包含的資訊有:名稱、別名、何處使用/如何使用、內容描述、補充資訊等。
3、判定樹
使用判定樹進行描述時,應先從問題定義的文字描述中分清哪些是判定條件,哪些是判定結論,根據描述材料中的串連詞找出判定條件之間的從屬關係、並列關係、選擇關係,根據它們構造判定樹。
4、判定表
判定表和判定樹功能相似,當資料流圖中的加工要依賴於多個邏輯條件的取值,即完成該加工的一組動作是由於某一組條件取值的組合而引發的,使用判定表描述比較適宜。
判定由四部分組成:(1)基本條件;(2)條件項;(3)基本動作;(4)動作項
結構化分析的步驟如下:
①分析當前的情況,做出反映當前物理模型的DFD;
②推匯出等價的邏輯模型的DFD;
③設計新的邏輯系統,產生資料字典和基元描述;
④建立人機介面,提出可供選擇的目標系統物理模型的DFD;
⑤確定各種方案的成本和風險等級,據此對各種方案進行分析;
⑥選擇一種方案;
⑦建立完整的需求規約
結構化設計
在結構化分析階段,我們產生了資料流圖。結構化的設計能方便的將資料流圖轉換為軟體結構圖。資料流圖從系統中的輸入資料流到系統的輸出資料流的一連串聯續變換形成了一條資訊流。根據資料流類型不同,可分為變換型和事務型2類,事務型和變換型資料流的設計步驟基本是大同小異,它們之間主要差別就是從資料流圖到軟體結構的映射方法不同。因此在進行軟體結構設計時,首先對資料流圖進行分析,然後判斷屬於哪一種類型,根據不同的資料流類型,通過一系列映射,把資料流圖轉換為軟體結構圖。具體過程見圖一。
圖一 資料流程圖轉換為軟體結構圖基本流程
結構化設計方法是設計軟體體繫結構的一種系統化的方法,根據不同的映射規則,可以把資料流圖變換成軟體的初步結構圖。得出軟體的初始結構圖之後,還必鬚根據結構化設計的基本原則和有關啟發規則,對所得到的初始軟體結構圖進行仔細最佳化,才能設計出令人滿意的軟體體繫結構。
結構化編碼
結構化編碼的核心是模組化思想以及自頂向下的程式設計思想,這兩者是相輔相成的。現代軟體工程的特點之一即是項目規模大,以至於開發人員很難,甚至是無法有效對代碼品質進行把握。因而自頂向下的編碼思想被提出,通過對於原始問題進行層層分解,人們不需要直接面對大規模的複雜系統,而是每次只需關心一個局部的問題。而對於這樣局部的問題,則可以設計模組來進行解決(在實踐中往往是使用函數來實現模組)。
圖2 自頂向下分解任務
物件導向方法
與結構化方法類似,物件導向方法包括物件導向分析(OOA)、物件導向設計(OOD)及物件導向程式設計(OOP)3部分內容。
物件導向分析
是在一個系統的開發過程中進行了系統業務調查以後,按照物件導向的思想來分析問題。OOA與結構化分析有較大的區別。OOA所強調的是在系統調查資料的基礎上,針對OO方法所需要的素材進行的歸類分析和整理,而不是對管理業務現狀和方法的分析。
OOA模型由5個層次(主題層、對象類層、結構層、屬性層和服務層)和5個活動(標識對象類、標識結構、定義主題、定義屬性和定義服務)組成。在這種方法中定義了兩種對象類之間的結構,一種稱為分類結構,一種稱為組裝結構。分類結構就是所謂的一般與特殊的關係。組裝結構則反映了對象之間的整體與部分的關係。
OOA在定義屬性的同時,要識別執行個體串連。執行個體串連是一個執行個體與另一個執行個體的映射關係。OOA在定義服務的同時要識別訊息串連。當一個對象需要向另一對象發送訊息時,它們之間就存在訊息串連。
OOA的原則主要有以下幾條:
(1)抽象:從許多事物中捨棄個別的、非本質的特徵,抽取共同的、本質性的特徵,就叫作抽象。抽象是形成概念的必須手段。抽象原則有兩方面的意義:第一,儘管問題域中的事物是很複雜的,但是分析員並不需要瞭解和描述它們的一切,只需要分析研究其中與系統目標有關的事物及其本質性特徵。第二,通過捨棄個體事物在細節上的差異,抽取其共同特徵而得到一批事物的抽象概念。
(2)封裝:就是把對象的屬性和服務結合為一個不可分的系統單位,並儘可能隱蔽對象的內部細節。
(3)繼承:特殊類的對象擁有的其一般類的全部屬性與服務,稱作特殊類對一般類的繼承。
物件導向設計
物件導向設計(Object-Oriented Design,OOD)方法是OO方法中一個中間過渡環節。其主要作用是對OOA分析的結果作進一步的正常化整理,以便能夠被OOP直接接受。
物件導向設計(OOD)是一種軟體設計方法,是一種工程化規範。其主要包括以下幾項工作:
- 決定你要的類;
- 給每個類提供完整的一組操作;
- 明確地使用繼承來表現共同點。
由這個定義,我們可以看出:OOD就是“根據需求決定所需的類、類的操作以及類之間關聯的過程”。
OOD的目標是管理程式內部各部分的相互依賴。為了達到這個目標,OOD要求將程式分成塊,每個塊的規模應該小到可以管理的程度,然後分別將各個塊隱藏在介面(interface)的後面,讓它們只通過介面相互交流。
物件導向程式設計
OOP是在結構化程式設計的基礎上,於80年代初湧現的一種程式設計方法,但其真正顯示力量和被產業界所重視還是最近幾年的事。封裝是整個OOP方法的基礎,主要用於在資料區段外圍構造保護層,以限制外界變化的影響,所有的資料訪問都由保護層內的過程間接處理。應用程式員不必再按照將程式設計語言逐句拼裝的方式來構造整個軟體,只需組合、重用由系統程式員開發、可供他人用來裝配的軟體整合塊即可。
OOP 達到了軟體工程的三個主要目標:重用性、靈活性和擴充性。為了實現整體運算,每個對象都能夠接收資訊、處理資料和向其它對象發送資訊。OOP 主要有以下主要的概念:
組件:資料和功能一起在運行著的電腦程式中形成的單元,組件在 OOP 電腦程式中是模組和結構化的基礎。
1. 抽象性:程式有能力忽略正在處理中資訊的某些方面,即對資訊主要方面關注的能力。
2. 封裝:確保組件不會以不可預期的方式改變其它組件的內部狀態;只有在那些提供了內部狀態改變方法的組件中,才可以訪問其內部狀態。每類組件都提供了一個與其它組件聯絡的介面,並規定了其它組件進行調用的方法。
3. 多態性:組件的引用和類集會涉及到其它許多不同類型的組件,而且引用組件所產生的結果得依據實際調用的類型。
4. 繼承性:允許在現存的組件基礎上建立子類組件,這統一併增強了多態性和封裝性。典型地來說就是用類來對組件進行分組,而且還可以定義新類為現存的類的擴充,這樣就可以將類組織成樹形或網狀結構,這體現了動作的通用性。
結構化方法 V.S 物件導向方法
從上面的介紹與分析中,我們可以總結出:結構化方法中,資料與操作以鬆散的方式聯絡在一起,資料往往能夠被多個操作訪問,它可能在開發人員不知道的情況下被修改(可以想象,在大型多人開發項目中,這種情況會頻繁發生),從而導致難於調試的運行錯誤。此種情況會增大程式理解的複雜度,以及驗證程式正確性的成本;而與此相對,物件導向方法,通過使用對象,將資料與操作緊密結合到了一起,每個對象通過資料隱藏,自主管理其狀態(即資料),這使得驗證程式的正確性成為了可能,同時由於資料處理的局部化,對於程式的理解也更加簡單。
除此之外,結構化方法中,程式的基本單元是模組,及處理事務的步驟,在主函數中,只要一次調用各個模組即可解決問題;而物件導向方法中,程式的基本單元是對象,每個對象都刻畫了問題處理過程中的某一個事物。
舉個例子來說,假如我們要設計一個簡單的五子棋遊戲。按照結構化的方法,就是首先分析問題的步驟:1、開始遊戲; 2、黑子先走; 3、繪製畫面;4、判斷輸贏,如果黑勝則跳到9,否則繼續執行5;5、輪到白子;6、繪製畫面;7、判斷輸贏,如果白勝則調到9,否則繼續到8;8、返回步驟2;9、輸出最後結果。
而如果按照物件導向的方法來設計,首先需要識別出整個系統中有哪些類。那麼經過分析,我們發現整個五子棋可以分為 1、黑白雙方,這兩方的行為是一模一樣的;2、棋盤系統,負責繪製畫面;3、規則系統,負責判定諸如犯規、輸贏等。第一類對象(玩家對象)負責接受使用者輸入,並告知第二類對象(棋盤對象)棋子布局的變化,棋盤對象接收到了棋子的i變化就要負責在螢幕上面顯示出這種變化,同時利用第三類對象(規則系統)來對棋局進行判定。
從這組比較中,我們可以發現,雖然兩種方法都比較直觀,最終也都解決了問題,但顯然物件導向方法設計起來更加自然,因為其基本元素與其功能劃分直接產生於現實世界,而結構化方法則需要再對整個流程進行分析,從而才能設計出各個步驟。此外,我們還能夠發現,物件導向方法直接考慮的是功能,而非更加細化的步驟,這在減少思考的複雜度的同時,也更便於應對實際需求中經常會遇到的需求變化而導致的相應功能變化;而相應的,由於功能被拆分到各個步驟中去,結構化方法在遇到這種情況時,往往會非常痛苦。
仍以剛剛的系統為例,如果需求方提出,不僅要做五子棋遊戲,要做一個棋類遊戲集合,即要求遊戲規則可以有多種選擇(五子棋規則,圍棋規則等等)。如果是結構化方法,因為各個模組較為獨立,每個模組都需要涉及到遊戲規則,而非像物件導向方法中的集中到同一個對象中,那麼可以想象,這時如果要更改遊戲規則是非常痛苦的(更不用說在此種情況下是要允許使用者自由選擇遊戲規則),甚至不如推倒重做。而如果按照物件導向方法的設計,只需要改動規則對象,增加幾個選擇分支,使其能夠對於不同的勝利條件進行判斷即可,對於整個系統來說,其餘部分幾乎不需要改動。
然而物件導向方法也非毫無缺點,最突出的一點,即是其在效能上往往與結構化方法實現的系統有很大的差距,原因之一在於其天生對於並發的支援力度很弱。由於對象是有狀態的,那麼每次調用同一方法時,往往會返回不同的結果(如取某個屬性的值)。而這就導致並發執行時,各個線程執行的順序對於程式的正確性至關重要(因而我們需要各種各樣的鎖來滿足開發的需求),因而我們要為了安全執行緒而降低程式的並發程度,從而拖慢程式速度。而無狀態的函數則不會遇到這些問題。另一個原因在於,物件導向方法的提出本就不是為瞭解決效率問題,而是簡化軟體設計、開發、維護的過程,這一點從上面的例子中也能夠看出。而這樣的簡化不可避免的會以犧牲效率為代價。而結構化方法,由於從設計階段開始就直接涉及底層的資料結構和演算法,因而可以更加方便地進行最佳化。
在認識到二者區別的同時,我們也需要意識到結構化方法與物件導向方法並不是相互對立的。首先來說,OOP是SP的超集。一段典型的結構化程式如下:
... Program startvarvarvarfunction {...}function {...}function {...}main {...}... Program End
首先是變數定義,之後函數定義,最後主函數中調用各個函數。而與之對應的物件導向程式碼如下:
... Program startObject {VarVarfunction {...}function {...}function {...}}main [...}... Program End
首先定義類,類中定義屬性(對應於變數)與方法(對應於函數),之後在主函數中執行個體化對象並調用其相應的方法即可。這一特性也使得很多初學者會以物件導向之虛行面向過程之實。我們甚至可以說,物件導向方法是結構化方法發展而來,因為它繼承了很多結構化方法中的成功經驗:資料抽象、自頂向下、模組化、高內聚、低耦合等。
總結
本文首先介紹了結構化方法與物件導向方法的概念與基本實現步驟。結構化方法的核心在於模組化思想,而物件導向方法核心在於資料與操作的抽象以及封裝。通過結合執行個體的比較,我們發現,物件導向方法更加貼合實際,設計、實現與維護起來相較於結構化方法都更加簡單,而其缺點則在於對於並發的支援力度不足,從而導致代碼執行效率與結構化方法實現的程式相比較低,往往需要結合後續的分析與最佳化。然而,我們也要認識到,物件導向方法與結構化方法並不是對立的,從某種角度來說,我們甚至可以將物件導向方法看做是由結構化方法發展而來。物件導向方法繼承了很多結構化方法中的成功經驗如:資料抽象、自頂向下、模組化、高內聚、低耦合等,因而可以說是結構化方法的實踐經驗的整合。在實際項目中,結構化方法更為適合小型項目,然而當資料量增大時,資料與處理這些資料的方法之間的分離使程式變得越來越難以理解。對資料處理能力的需求越強,這種分離所造成的負面影響越顯著,這時物件導向方法則顯得更為合適。
結構化方法與物件導向方法之比較