?
軟件開發的相關技術
??????????????????????作者:naven
2005-5-10
?
1
、
Rational
統一開發過程(
Rational Unified Process
簡稱
RUP
)
是軟件開發隊伍的最佳實踐
?
什么是
Rational Unified Process
RUP
是軟件工程化過程它提供了在開發機構中分派任務和責任的紀律化方法它的目標是在可預見的日程和預算前提下確保滿足最終用戶需求的高質量產品
RUP
是有效使用
Unified Modeling Language
(
UML
)的指南。是良好溝通需求體系結構和設計的工業標準語言。
UML
是由
Rational
軟件公司創建現在由標準化對象管理機構(
OMG
)維護
?
“統一過程”概述
“統一過程”是軟件開發過程。軟件開發過程是將用戶的需求轉化為一個軟件系統的一系列活動的總稱。然而,“統一過程”不僅僅是一個過程。它是一個通用過程框架,可以應付種類廣泛的軟件系統、不同的應用領域、不同的組織類型、不同的性能水平和不同的項目規模。
“統一過程”是基于組件的,這意味著利用它開發的軟件系統是由組件構成的,組件之間通過定義良好的接口相互聯系
。
在準備軟件系統的所有藍圖的時候,“統一過程”使用的是“統一建模語言(
Unified Modeling anguage
)”。事實上,
UML
是“統一過程”的有機組成部分——它們是被同步開發的
。
然而,真正使“統一過程”與眾不同的方面可以用三個句話來表達:它是用例驅動的、以基本架構為中心的、迭代式和增量性的。正是這些特征使得“統一過程”卓爾不群。
“統一過程”是用例驅動的“統一過程”是用例驅動的“統一過程”是用例驅動的“統一過程”是用例驅動的開發軟件系統的目的是要為該軟件系統的用戶服務。因此,要創建一個成功的軟件系統,我們必須明白其潛在用戶需要什么
。
?
2
、統一模語言
UML
概述
標準建模語言
UML
的重要內容可以由下列五類圖
(
共
9
種圖形
)
來定義
:
·第一類是用例圖
,
從用戶角度描述系統功能
,
并指出各功能的操作者。
·第二類是靜態圖
(Static diagram),
包括類圖、對象圖和包圖。其中類圖描述系統中類的靜態結構。不僅定義系統中的類
,
表示類之間的聯系如關聯、依賴、聚合等
,
也包括類的內部結構
(
類的屬性和操作
)
。類圖描述的是一種靜態關系
,
在系統的整個生命周期都是有效的。對象圖是類圖的實例
,
幾乎使用與類圖完全相同的標識。他們的不同點在于對象圖顯示類的多個對象實例
,
而不是實際的類。一個對象圖是類圖的一個實例。由于對象存在生命周期
,
因此對象圖只能在系統某一時間段存在。包由包或類組成
,
表示包與包之間的關系。包圖用于描述系統的分層結構。
·第三類是行為圖
(Behavior diagram),
描述系統的動態模型和組成對象間的交互關系。
·第四類是交互圖
(Interactive diagram),
描述對象間的交互關系。
·第五類是實現圖
( Implementation diagram )
。
?
RUP
及
UML
缺點:過于復雜甚至有些啰嗦。
?
?
3
、面向對象軟件開發和過程
A
代碼是軟件開發的基礎
編碼是軟件開發過程中最基本、最底層的技藝,然而也是最重要的技藝。任何一個領域的專家都需要花費大量的時間來進行基本技藝的鍛煉,木匠需要花費大量的時間來鍛煉他們對各種工具的掌握,廚師則需要練習刀工和火候。程序員也是一樣的,對我們來說,語言的各種特性必須要了然于胸。而對軟件的管理也需要從代碼做起。
面向對象的代碼已經在現在的軟件開發中占據了主流的位置,面向對象的思路也有其優勢所在,就像后文所討論的,面向對象代碼有著非面向對象代碼的很多優勢,而軟件業中很多新的思潮的產生,也都是基于面向對象語言的,所以我們關注的代碼將是面向對象代碼。
編寫優秀的面向對象代碼并不是一件容易的事情,優秀的
OO
代碼如行云流水,糟糕的
OO
代碼讓人覺得渾身起雞皮疙瘩。編寫優秀的
OO
代碼要求程序員有一定的自我修養,能夠以抽象的思路看待問題,找到問題的核心并對問題域進行分解。它強調的是一種解題的思路,但這個解不是唯一的。
編寫優秀
OO
代碼雖難,但還有更難的事情,就是讓整個開發團隊都產出優秀的
OO
代碼。
?
B
面向對象軟件開發過程
普通的軟件開發過程和面向對象開發過程有著很大的不同。回想我們在非面向對象中開發過程中,最經常采用的任務分配方法就是以軟件模塊為單位,這樣的好處是分配簡單,不同任務之間耦合程度低,容易操作。壞處是幾乎無法做到重用,也缺乏整體性的設計。而面向對象軟件開發則不同,它是以類、類集合作為基本單位的。類之間關系錯綜復雜(雖然我們提倡低耦合的設計,但類之間的關系仍然是相對復雜的)。這種情況下程序員之間相互協作的要求就非常之高,這種關系如果處理恰當,則能夠完全體現出面向對象的威力,否則,那將會是一場大災難,面向對象的軟件開發過程要養成一些好的習慣:盡量簡化和穩定客戶端。準備一份簡潔的文檔,并保持更新。盡可能多的考慮異常和錯誤的情況。
?
C
基于面向對象代碼的分析框架
在一個開發過程中,往往有著多種復雜的因素:過程、技能、工具、規范、組織、個性。所有的這些,都會對最終的代碼產生影響,對代碼的成本和質量產生影響。軟件最有價值的部分是代碼,根據敏捷方法和精益編程的思路,除了代碼之外的產出物,都不具有價值,或者說對最終用戶沒有價值。但它們都需要成本的投入,而我們應該考慮如何節省這些成本。
?
?
4
、應用框架
框架不是框框—應用框架的基本思想
軟件構件化是
21
世紀軟件工業發展的大勢趨。工業化的軟件復用已經從通用類庫進化到了面向領域的應用框架。
Gartner Group
認為:“到
2003
年,至少
70%
的新應用將主要建立在如軟件構件和應用框架這類‘構造塊’之上;應用開發的未來就在于提供一開放體系結構,以方便構件的選擇、組裝和集成”。框架的重用已成為軟件生產中最有效的重用方式之一。
什么是框架?
框架(
Framework
)是整個或部分系統的可重用設計,表現為一組抽象構件及構件實例間交互的方法
;
另一種定義認為,框架是可被應用開發者定制的應用骨架。前者是從應用方面而后者是從目的方面給出的定義。
可以說,一個框架是一個可復用的設計構件,它規定了應用的體系結構,闡明了整個設計、協作構件之間的依賴關系、責任分配和控制流程,表現為一組抽象類以及其實例之間協作的方法,它為構件復用提供了上下文
(Context)
關系。因此構件庫的大規模重用也需要框架。
框架和設計模式
框架、設計模式這兩個概念總容易被混淆,其實它們之間還是有區別的。構件通常是代碼重用,而設計模式是設計重用,框架則介于兩者之間,部分代碼重用,部分設計重用,有時分析也可重用。在軟件生產中有三種級別的重用:內部重用,即在同一應用中能公共使用的抽象塊
;
代碼重用,即將通用模塊組合成庫或工具集,以便在多個應用和領域都能使用;應用框架的重用,即為專用領域提供通用的或現成的基礎結構,以獲得最高級別的重用性。
為什么要進行框架開發
?
框架的最大好處就是重用。面向對象系統獲得的最大的復用方式就是框架,一個大的應用系統往往可能由多層互相協作的框架組成。
由于框架能重用代碼,因此從一已有構件庫中建立應用變得非常容易,因為構件都采用框架統一定義的接口,從而使構件間的通信簡單。
框架能重用設計。它提供可重用的抽象算法及高層設計,并能將大系統分解成更小的構件,而且能描述構件間的內部接口。這些標準接口使在已有的構件基礎上通過組裝建立各種各樣的系統成為可能。只要符合接口定義,新的構件就能插入框架中,構件設計者就能重用構架的設計。
框架還能重用分析。所有的人員若按照框架的思想來分析事務,那么就能將它劃分為同樣的構件,采用相似的解決方法,從而使采用同一框架的分析人員之間能進行溝通。
有利于在一個項目內多人協同工作;
大粒度的重用使得平均開發費用降低,開發速度加快,開發人員減少,維護費用降低,而參數化框架使得適應性、靈活性增強。
框架能使應用程序的開發簡單,價格低廉,但是開發框架不是一件容易的事。它是一個需要領域和設計經驗的反復過程。為了保證框架的靈活性,必須提取和發現熱點。設計模式可以簡化這個過程,因為它提供了對過去經驗的抽象。應用框架能高度抽象同一領域內的問題,進而降低開發難度和強度。雖然框架和構件技術已經出現許多年了,開始走入實用
,
但還不成熟,有大量問題有待研究。
?
?
5
、模塊化和構件化設計
?
?
?
6
、概要設計怎么做
在需求明確、準備開始編碼之前,要做概要設計,而詳細設計可能大部分公司沒有做,有做的也大部分是和編碼同步進行,或者在編碼之后。因此,對大部分的公司來說,概要設計文檔是唯一的設計文檔,對后面的開發、測試、實施、維護工作起到關鍵性的影響。
大的系統的概要設計相當于架構設計和初步的系統設計。
?
概要設計的目的(架構設計)
將軟件系統需求轉換為未來系統的設計;
逐步開發強壯的系統構架;
使設計適合于實施環境,為提高性能而進行設計;
結構應該被分解為模塊和庫。
概要設計的任務
制定規范:代碼體系、接口規約、命名規則。這是項目小組今后共同作戰的基礎,有了開發規范和程序模塊之間和項目成員彼此之間的接口規則、方式方法,大家就有了共同的工作語言、共同的工作平臺,使整個軟件開發工作可以協調有序地進行。
總體結構設計:
?
功能(加工)-
>
模塊:每個功能用那些模塊實現,保證每個功能都有相應的模塊來實現;
?
模塊層次結構:某個角度的軟件框架視圖;
?
模塊間的調用關系:模塊間的接口的總體描述;
?
模塊間的接口:傳遞的信息及其結構;
?
處理方式設計:滿足功能和性能的算法
?
用戶界面設計;
?
數據結構設計:
?
詳細的數據結構:表、索引、文件;
?
算法相關邏輯數據結構及其操作;
?
上述操作的程序模塊說明(在前臺?在后臺?用視圖?用過程?······)
?
接口控制表的數據結構和使用規則
?
其他性能設計。
概要設計寫什么
?
結構化軟件設計說明書結構(因篇幅有限和過時嫌疑,在此不作過多解釋)
?
任務:目標、環境、需求、局限;
?
總體設計:處理流程、總體結構與模塊、功能與模塊的關系;
?
接口設計:總體說明外部用戶、軟、硬件接口;內部模塊間接口(注:接口≈系統界面)
?
數據結構:邏輯結構、物理結構,與程序結構的關系;
?
模塊設計:每個模塊“做什么”、簡要說明“怎么做”(輸入、輸出、處理邏輯、與其它模塊的接口,與其它系統或硬件的接口),處在什么邏輯位置、物理位置;
?
運行設計:運行模塊組合、控制、時間;
?
出錯設計:出錯信息、處錯處理;
?
其他設計:保密、維護;
?
7
、代碼規范和注釋規范
?
?
?
8
、單元測試和測試案例
?
?
9
、團隊協作及大中規模軟件開發過程
大規模軟件需要團隊合作開發。
?
第一步:需求分析,產出
Use-Case
用例圖
第二步:概要設計,產出概要設計文檔(模塊設計和代碼規范等)
第三步:架構設計,產出模塊化設計,功能設計,接口設計,模塊協作圖等圖及文檔
第四步:系統設計,產出
Sequence
序列圖,功能流程程圖
第五步:詳細設計,產出
Class
類圖,偽代碼設計,測試案例等
第六步:代碼開發及單元測試
第七步:壓力測試和整體聯調測試
第八步:完成后續文檔和維護文檔等
?
?
?
10
、面向對象設計原則
The OpenThe Open--Closed PrincipleClosed Principle
任何系統在其生命周期中都會發生變化。如果我們希望開發出的系統不會在第一版本后就被拋棄,那么我們就必須牢牢記住這一點。
軟件組成實體(類,模塊,函數,等等)應該是可擴展的,但是不可修改的。
?
OCP OCP
特征
1
、可擴展(對擴展是開放的)
模塊的行為功能可以被擴展,在應用需求改變或需要滿足新的應用需求時,我們可以讓模塊以不同的方式工作
2
、不可更改(對更改是封閉的)
這些模塊的源代碼是不可改動的。任何人都不許修改模塊的源代碼。
?
關鍵是抽象!
模塊可以操作一個抽象體。由于模塊依賴于一個固定的抽象體,因此它可以是不允許修改(
closed for modification
)的;同時,通過從這個抽象體派生,也可擴展此模塊的行為功能。
符合
OCP
原則的程序只通過增加代碼來變化而不是通過更改現有代碼來變化,因此這樣的程序就不會引起象非開放―封閉(
open-closed
)的程序那樣的連鎖反應的變化。
?
對可變性的封裝
考慮系統中什么可能會發生變化
一種可變性不應當散落在代碼的很多角落里,而應當被封裝到一個對象里
?
正確理解繼承
一種可變性不應當與另一個可變性混合在一起
?
選擇性的封閉(
Strategic Closure
)沒有任何一個大的程序能夠做到
100%
的封閉。一般來講,無論模塊是多么的“封閉”,都會存在一些無法對之封閉的變化。既然不可能完全封閉,因此就必須選擇性地對待這個問題。也就是說,設計者必須對于他(她)設計的模塊應該對何種變化封閉做出選擇。
?
?
Liskov
替換原則替換原則
LSP The The Liskov Substitution Principle
OCP
原則背后的主要機制是抽象和多態。支持抽象和多態的關鍵機制是繼承。
?
LSP
的定義
若對于每一個類型
S
的對象
o1
,都存在一個類型
T
的對象
o2
,使得在所有針對
T
編寫的程序
P
中,用
o1
替換
o2
后,程序
P
的行為功能不變,則
S
是
T
的子類型。
LSP
原則清楚地指出,
OOD
中
Is-A
關系是就行為功能而言。行為功能(
behavior
)不是內在的、私有的,而是外在、公開的,是客戶程序所依賴的。行為功能(
behavior
)才是軟件所關注的問題!所有派生類的行為功能必須和客戶程序對其基類所期望的保持一致。
?
LSP
和
DBC
DBC
(
Design by Contract
)定義把類和其客戶之間的關系看作是一個正式的協議,明確各方的權利和義務。
DBC
對類的要求類的方法聲明為先決條件(
precondition
)和后續條件(
postcondition
)。為了讓方法得以執行,先決條件必須為真。完成后,方法保證后續條件為真。
DBC
對派生類的要求當重新定義派生類中的例行程序時,我們只能用更弱的先決條件和更強的后續條件替換之。
?
LSP
-結論
LSP
原則是符合
OCP
原則應用程序的一項重要特性。僅當派生類能完全替換基類時,我們才能放心地重用那些使用基類的函數和修改派生類型。
高層模塊不應該依賴于低層模塊。二者都應該依賴于抽象。
抽象不應該依賴于細節。細節應該依賴于抽象。
實施重點
從問題的具體細節中分離出抽象,以抽象方式對類進行耦合
不足
導致生成大量的類
假定所有的具體類都是會變化的,這也不總是正確的
DIP
與設計模式
DIP
以
LSP
為基礎,是實現
OCP
的主要手段,是設計模式研究和應用的主要指導原則
接口的污染(
Interface Contamination
)一個沒有經驗的設計師往往想節省接口的數目,將一些功能相近或功能相關的接口合并,并將這看成是代碼優化的一部分。
定義:從一個客戶類的角度來講:一個類對另外一個類的依賴性應當是建立在最小的接口上的。使用多個專門的接口比使用單一的總接口要好。
合成
/
聚合復用原則(
CARP
)盡量使用合成
/
聚合、盡量不使用繼承
定義:在一個新的對象里面使用一些已有的對象,使之成為新對象的一部分;新的對象通過向這些對象的委派達到復用這些對象的目的。
?
?
11
、設計模式
在面向對象的編程中,軟件編程人員更加注重以前的代碼的重用性和可維護性。
設計模式使人們可以更加簡單方便地復用成功的設計和體系結構。將已證實的技術表述成設計模式也會使新系統開發者更加容易理解其設計思路。
?
一般而言,一個模式有四個基本要素
1.
模式名稱(
pattern name
)
一個助記名,它用一兩個詞來描述模式的問題、解決方案和效果。命名一個新的模式增加了我們的設計詞匯。設計模式允許我們在較高的抽象層次上進行設計。基于一個模式詞匯表,我們自己以及同事之間就可以討論模式并在編寫文檔時使用它們。模式名可以幫助我們思考,便于我們與其他人交流設計思想及設計結果。找到恰當的模式名也是我們設計模式編目工作的難點之一。
2.
問題
(problem)
描述了應該在何時使用模式。它解釋了設計問題和問題存在的前因后果,它可能描述了特定的設計問題,如怎樣用對象表示算法等。也可能描述了導致不靈活設計的類或對象結構。有時候,問題部分會包括使用模式必須滿足的一系列先決條件。
3.
解決方案
(solution)
描述了設計的組成成分,它們之間的相互關系及各自的職責和協作方式。因為模式就像一個模板,可應用于多種不同場合,所以解決方案并不描述一個特定而具體的設計或實現,而是提供設計問題的抽象描述和怎樣用一個具有一般意義的元素組合(類或對象組合)來解決這個問題。
4.
效果
(consequences)
描述了模式應用的效果及使用模式應權衡的問題。盡管我們描述設計決策時,并不總提到模式效果,但它們對于評價設計選擇和理解使用模式的代價及好處具有重要意義。軟件效果大多關注對時間和空間的衡量,它們也表述了語言和實現問題。因為復用是面向對象設計的要素之一,所以模式效果包括它對系統的靈活性、擴充性或可移植性的影響,顯式地列出這些效果對理解和評價這些模式很有幫助。
?
一些基本的設計模式
Abstract Factory
:提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們具體的類。
Adapter
:將一個類的接口轉換成客戶希望的另外一個接口。
A d a p t e r
模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
Bridge
:將抽象部分與它的實現部分分離,使它們都可以獨立地變化。
Builder
:將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
Chain of Responsibility
:為解除請求的發送者和接收者之間耦合,而使多個對象都有機會處理這個請求。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它。
Command
:將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日志,以及支持可取消的操作。
Composite
:將對象組合成樹形結構以表示“部分
-
整體”的層次結構。它使得客戶對單個對象和復合對象的使用具有一致性。
Decorator
:動態地給一個對象添加一些額外的職責。就擴展功能而言,
它比生成子類方式更為靈活。
Facade
:為子系統中的一組接口提供一個一致的界面,
F a c a d e
模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。
Factory Method
:定義一個用于創建對象的接口,讓子類決定將哪一個類實例化。
Factory Method
使一個類的實例化延遲到其子類。
Flyweight
:運用共享技術有效地支持大量細粒度的對象。
Interpreter
:給定一個語言
,
定義它的文法的一種表示,并定義一個解釋器
,
該解釋器使用該表示來解釋語言中的句子。
Iterator
:提供一種方法順序訪問一個聚合對象中各個元素
,
而又不需暴露該對象的內部表示。
Mediator
:用一個中介對象來封裝一系列的對象交互。中介者使各對象不需要顯式地相互引用,從而使其耦合松散,而且可以獨立地改變它們之間的交互。
Memento
:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態。這樣以后就可將該對象恢復到保存的狀態。
Observer
:定義對象間的一種一對多的依賴關系
,
以便當一個對象的狀態發生改變時
,
所有依賴于它的對象都得到通知并自動刷新。
Prototype
:用原型實例指定創建對象的種類,并且通過拷貝這個原型來創建新的對象。
Proxy
:為其他對象提供一個代理以控制對這個對象的訪問。
Singleton
:保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
State
:允許一個對象在其內部狀態改變時改變它的行為。對象看起來似乎修改了它所屬的類。
Strategy
:定義一系列的算法
,
把它們一個個封裝起來
,
并且使它們可相互替換。本模式使得算法的變化可獨立于使用它的客戶。
Template Method
:定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。
Template Method
使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
Visitor
:表示一個作用于某對象結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。
?
?
12
、經驗談
1
、不迷信于某篇文章或某人或某一個理論,理解和領悟勝于死搬硬套,靈活運用
2
、用抽象的思維代替程序化的思維,找出事物的共性,分離出抽象的接口,可以不變應萬變,適應不同的需求。
3
、用對象代替數據,用成員方法代替函數來思考問題,設計系統。
4
、代碼要規范,注釋要規范。比如頭文件的包含關系,類型定義、聲明和實現的位置等,都需要有規范的統一。
5
、學會拿來主義,從別的優秀的系統中吸取自己想要的東西,而不是自己照搬照抄或者全部從零構建系統。
6
、框架是代碼的復用,設計模式是設計的復用,面向對象是設計的方法,
UML
是設計的工具,
RUP
是軟件開發的過程。
?
?
?
?
作者:naven? 2005-5-10
參考文獻:
1
、
www.uml.org.cn
、
2
、《
UML
:
Java
程序員指南》
?