OO設計模式和設計原則

OO設計模式和設計原則

作者: Cherami

    1.1 設計正在腐爛的徵兆(Symptoms of Rotting Design

    有四個主要的徵兆告訴我們該軟件設計正在腐爛中。它們並不是互相獨立的,而是互相關聯,它們是過於僵硬、過於脆弱、不可重用性和粘滯性過高。

    1. 過於僵硬Rigidity Rigidity 致使軟件難以更改,每一個改動都會造成一連串的互相依靠的模塊的改動,項目經理不敢改動,因爲他永遠也不知道一個改動何時才能完成。

    2. 過於脆弱Fragility Fragility 致使當軟件改動時,系統會在許多地方出錯。並且錯誤經常會發生在概念上與改動的地方沒有聯繫的模塊中。這樣的軟件無法維護,每一次維護都使軟件變得更加難以維護。(惡性循環)

    3. 不可重用性immobility immobility 致使我們不能重用在其它項目中、或本項目中其它位置中的軟件。工程師發現將他想重用的部分分離出來的工作量和風險太大,足以抵消他重用的積極性,因此軟件用重寫代替了重用。

    4. 粘滯性過高viscosity viscosity有兩種形式:設計的viscosity和環境的viscosity.當需要進行改動時,工程師通常發現有不止一個方法可以達到目的。但是這些方法中,一些會保留原有的設計不變,而另外一些則不會(也就是說,這些人是hacks)。一個設計如果使工程師作錯比作對容易得多,那麼這個設計的viscosity 就會很高。

    環境的viscosity高是指開發環境速度很慢且效率很低。

    2 面向對象的類設計原則

    2.1 開放關閉原則The Open Closed Principle OCP

    A module should be open for extension but closed for modification.一個模塊應該只在擴展的時候被打開(暴露模塊內部),在修改的時候是關閉的(模塊是黑盒子)。

    在所有的面向對象設計原則中,這一條最重要。該原則是說:我們應該能夠不用修改模塊的源代碼,就能更改模塊的行爲。

    2.1.1 動態多態性(Dynamic Polymorphism

    2.1.2 靜態多態性(Static Polymorphism

    另外一種使用OCP的技術就是使用模板或範型,如Listing 2-3.LogOn函數不用修改代碼就可以擴展出多種類型的modem. 2.1.3 OCP的體系結構目標(Architectural Goals of the OCP

    通過遵照OCP應用這些技術,我們能創建不用更改內部代碼就可以被擴展的模塊。這就是說,在將來我們給模塊增添新功能是,只要增加新的代碼,而不用更改原先的代碼。 3 頁,共 17 頁使軟件完全符合OCP可能是很難的,但即使只是部分符合OCP,整個軟件的結構性能也會有很大的提高。我們應該記住,讓變化不要波及已經正常工作的代碼總是好的。

    2.2 Liskov 替換原則The Liskov Substitution PrincipleLSP

    Subclasses should be substitutable for their base classes.子類應該可以替換其基類。

    如下圖2-14所示。Derived類應該能替換其Base類。也就是說,Base基類的一個用戶User如果被傳遞給一個Devrived類而不是Base類作爲參數,也能正常的工作。

    2.3 依賴性倒置原則The Dependency Inversion Principle DIP1

     Depend upon Abstractions. Do not depend upon concretions.依賴抽象,不要依賴具體。

    如果說OCP聲明瞭OO體系結構的目的,DIP則闡述了其主要機制。依賴性倒置的策略就是要依賴接口、或抽象函數、或抽象類,而不是依賴於具體的函數和類。這條原則就是支持組件設計、COMCORBAEJB等等的背後力量。

    2.3.1 依賴抽象Depending upon Abstractions.

    實現該原則十分簡單。設計中的每一個依賴都應該是接口、抽象類,不要依賴任何一個具體類。

    顯然這樣的限制比較嚴峻,但是我們應該儘可能的遵守這條原則。原因很簡單,具體的模塊變化太多,抽象的則變化少得多。而且,抽象是鉸鏈點,在這些位置,設計可以彎曲或者擴展,而不用進行更改(OCP)。

    2.4 接口隔離原則The Interface Segregation Principle ISP

    ‘Many client specific interfaces are better than one general purpose interface多個和客戶相關的接口要好於一個通用接口。

    ISP是另一條在底層支持組件如COM技術的原則。沒有它,組件和類的易用性和重用性都會大打折扣。該原則的實質很簡單:如果一個類有幾個使用者,與其讓這個類載入所有使用者需要使用的所有方法,還不如爲每一個使用者創建一個特定的接口,並讓該類分別實現這些接口。

    3 包體系結構的原則Principles of Package Architecture

    類是必不可少的,但對於組織一個設計來說還不夠,粒度更大的包有助於此。但是我們應該怎樣協調類和包之間的從屬關係?下面的三條原則都屬於包聚合原則,能對我們有所幫助。

    3.1 包聚合原則

    3.1.1 發佈重用等價原則The Release Reuse Equivalency Principle REP1

    重用的粒度就是發佈的粒度。The granule of reuse is the granule of release.一個可重用的元件(組件、一個類、一組類等),只有在它們被某種發佈(Release)系統管理以後,才能被重用。用戶不願意使用那些每次改動以後都要被強迫升級的元件。因此,即使開發者發佈了可重用元件的新版本,他也必須支持和維護舊版本,這樣纔有時間讓用戶熟悉新版本。

    因此,將什麼類放在一個包中的判斷標準之一就是重用,並且因爲包是發佈的最小單元,它們同樣也是重用的最小單元。體系結構師應該將可重用的類都放在包中。

    3.1.2 共同封閉原則The Common Closure Principle CCP2

   一起變化的類放在一起。Classes that change together belong together.一個大的開發項目通常分割成很多網狀互聯的包。管理、測試和發佈這些包的工作可不是微不足道的工作。在任何一個發佈的版本中,如果改動的包數量越多,重建、測試和部署也就會越多。因此我們應該儘量減少在產品的發佈週期中被改動的包的數量,這就要求我們將一起變化的類放在一起(同一個包)。

    3.1.3 共同重用原則The Common Reuse Principle CRP3

    不一起重用的類不應該放在一起。Classes that aren‘t reused together should not be grouped together.對一個包的依賴就是對包裏面所有東西的依賴。當一個包改變時,這個包的所有使用者都必須驗證是否還能正常運行,即使它們所用到的沒有任何改變也不行。

    比如我們就經常遇到操作系統需要升級。當開發商發佈一個新版本以後,我們的升級是遲早的問題,因爲開發商將會不支持舊版本,即使我們對新版本沒有任何興趣,我們也得升級。

    如果把不一起使用的類放在一起,同樣的事情我們也會遇到。一個和我們無關的類的改變也產生包的一個新版本,我們被強迫升級和驗證這個包是否影響正常的運行。

    3.1.4 包聚合原則之間的張力Tension between the Package Cohesion Principles

    這三條原則實際上是互斥的。它們不能被同時滿足,因爲每一條原則都只針對某一方面,只對某一部分人有好處。REPCRP都想重用元件的人有好處,CCP對維護人員有好處。CCP使得包有儘可能大的趨勢(畢竟,如果所有的類都屬於一個包,那麼將只會有一個包變化);CRP儘量使得包更小。

    幸運的是,包並不是一成不變的。實際上,在開發過程中,包的轉義和增刪都是很正常的。在項目開發的早期,軟件建築師建立包的結構體系,此時CCP占主導地位,維護只是輔助。在體系結構穩定以後,軟件建築師會對包結構進行重構,此時儘可能的運用REPCRP,從而最大的方便重用元件的人員。

    3.2 包耦合原則The Package Coupling Principles.

   下面三條原則主要關心包之間的關係。

    3.2.1 無依賴迴路原則The Acyclic Dependencies Principle ADP1

    包與包之間的依賴不能形成迴路。The dependencies between packages must not form cycles.因爲包是發佈的粒度。人們傾向於節省人力資源,所以工程師們通常只編寫一個包而不是十幾個包。這種傾向由於包聚合原則被放大,後來人們就將相關的類組成一組。

    因此,工程師發現他們只會改動較少的幾個包,一旦這些改動完成,他們就可以發佈他們改動的包。但是在發佈前,他們必須進行測試。爲了測試,他們必須編譯和連編他們的包所依賴的所有的包。

    3.2.2 依賴穩定原則(Stable Dependencies PrincipleSDP

    朝穩定的方向依賴Depend in the direction of stability.雖然這條原則看起來很明顯,但是關於這方面還是有很多需要說明的地方,穩定性並不一定爲大家所瞭解。

    穩定性是什麼?站在一個硬幣上,這穩定嗎?很可能你說不。然而,除非被打擾,硬幣將保持那個位置很長時間。硬幣沒有變化,但是很難認爲它是穩定的。穩定性與需要改動所要做的工作量相關。硬幣不穩定是因爲只需要很小的工作量就能把它翻過來。換個角度,桌子就要穩定得多。

    對於軟件這說明什麼?一個軟件包很難被改動受很多因素影響:代碼大小、複雜度、透明度等等。這些我們先不說,可以肯定的一點是,如果有很多其它的包依賴於一個軟件包,那麼該軟件包就難以改動。一個包如果被許多其它包依賴,那麼該包是很穩定的,因爲這個包的任何一個改動都可能需要改動很多其它的包。

    3.2.3 穩定抽象原則( Stable Abstractions Principle SAP

    穩定的包應該是抽象包。Stable packages should be abstract packages.我們可以想象應用程序的包結構應該是一個互相聯繫的包的集合,其中不穩定的包在頂端,穩定的包在底部,所有的依賴方向朝下。那些頂端的包是不穩定而且靈活的,但那些底部的包就很難改動。這就導致一個兩難局面:我們想要將包設計爲難以改動的嗎?

    明顯地,難以改動的包越多,我們整個軟件設計的靈活性就越差。但是好像有一點希望解決這個問題,位於依賴網絡最底部的高穩定性的包的確難以改動,但是如果遵從OCP,這樣的包並不難以擴展。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章