單一職責原則
——SRP
就一個類而言,應該僅有一個引起它的變化的原因
?
原則
最簡單,最單純的事情最容易控制,最有效
類的職責簡單而且集中,避免相同的職責分散到不同的類之中,避免一個類承擔過多的職責
減少類之間的耦合
當需求變化時,只修改一個地方
組件
每個組件集中做好一件事情
組件的顆粒度
發布的成本
可重用的成本
?
方法
避免寫臃腫的方法
Extract Method
?
重構
Move Field/Move Class
Extract Method/Extract Class
?
最簡單的,也是最難以掌握的原則
?
實例分析
單一職責很容易理解,也很容易實現。所謂單一職責,就是一個設計元素只做一件事。什么是“只做一件事”?簡單說就是少管閑事。現實中就是如此,如果要你專心做一件事情,任何人都有信心可以做得很出色。但如果,你整天被亂七八糟的事所累,還有心思和精力把每件事都作好么?

?????
“單一職責”就是要在設計中為每種職責設計一個類,彼此保持正交,互不干涉。這個雕塑(二重奏)就是正交的一個例子,鋼琴家和小提琴家各自演奏自己的樂
譜,而結果就是一個和諧的交響樂。當然,真實世界中,演奏小提琴和彈鋼琴的必須是兩個人,但是在軟件中,我們往往會把兩者甚至更多攪和到一起,很多時候只
是為了方便或是最初設計的時候沒有想到。?
??????這樣的例子在設計中很常見,書中就給了一個很好的例子:調制解調器。這是一個調制
解調器最基本的功能。但是這個類事實上完成了兩個職責:連接的建立和中斷、數據的發送和接收。顯然,這違反了SRP。這樣做會有潛在的問題:當僅需要改變
數據連接方式時,必須修改Modem類,而修改Modem類的結果就是使得任何依賴Modem類的元素都需要重新編譯,不管它是不是用到了數據連接功能。
解決的辦法,書中也已經給出:重構Modem類,從中抽出兩個接口,一個專門負責連接、另一個專門負責數據發送。依賴Modem類的元素也要做相應的細
化,根據職責的不同分別依賴不同的接口。最后由ModemImplementation類實現這兩個接口。

??????從這個例子中,我們不難發現,違反SRP通常是由于過于“真實”地設計了一個類所造成的。因此,解決辦法是往更高一層進行抽象
化提取,將對某個具體類的依賴改變為對一組接口或抽象類的依賴。當然,這個抽象化的提取應該根據需要設計,而不是盲目提取。比如剛才這個Modem的例子
中,如果有必要,還可以把DataChannel抽象為DataSender和DataReceiver兩個接口。
開放封閉原則
——OCP
軟件實體(類,模塊,函數)應該是可以擴展的,但是不可修改的
?
原則
?
對擴展是開放的,當需求改變時我們可以對模塊進行擴展,使其具有新的功能
對更改是封閉的,對模塊擴展時,不需要改動原來的代碼
面對抽象而不是面對細節,抽象比細節活的更長
僵化的設計——如果程序中一處改動產生連鎖反應。
方法
條件case?? if/else 語句
?
重構
Replace Type Code With Class
Replace Type Code With State/Strategy
Replace Conditional with polymorphism
?
實例
開閉原則很簡單,一句話:“Closed for Modification; Open for Extension”——“對變更關閉;對擴展開放”。開閉原則其實沒什么好講的,我將其歸結為一個高層次的設計總則。就這一點來講,OCP的地位應該比SRP優先。
OCP的動機很簡單:軟件是變化的。不論是優質的設計還是低劣的設計都無法回避這一問題。OCP說明了軟件設計應該盡可能地使架構穩定而又容易滿足不同的需求。
為什么要OCP?答案也很簡單——重用。
“重用”,并不是什么軟件工程的專業詞匯,它是工程界所共用的詞匯。早在軟件出現前,工程師們就在實踐“重用”了。比如機械產品,通過零部
件的組裝得到最終的能夠使用的工具。由于機械部件的設計和制造過程是極其復雜的,所以互換性是一個重要的特性。一輛車可以用不同的發動機、不同的變速箱、
不同的輪胎……很多東西我們直接買來裝上就可以了。這也是一個OCP的例子。(可能是由于我是搞機械出身的吧,所以就舉些機械方面的例子^_^)。
如何在OO中引入OCP原則?把對實體的依賴改為對抽象的依賴就行了。下面的例子說明了這個過程:
05賽季的時候,一輛F1賽車有一臺V10引擎。但是到了06賽季,國際汽聯修改了規則,一輛F1賽車只能安裝一臺V8引擎。車隊很快投入了新賽車
的研發,不幸的是,從工程師那里得到消息,舊車身的設計不能夠裝進新研發的引擎。我們不得不為新的引擎重新打造車身,于是一輛新的賽車誕生了。但是,麻煩
的事接踵而來,國際汽聯頻頻修改規則,搞得設計師在“賽車”上改了又改,最終變得不成樣子,只能把它廢棄。
為了能夠重用這輛昂貴的賽車,工程師們提出了解決方案:首先,在車身的設計上預留出安裝引擎的位置和管線。然后,根據這些設計好的規范設計引擎(或是引擎的適配器)。于是,新的賽車設計方案就這樣誕生了。
?
顯然,通過重構,這里應用的是一個典型的Bridge模式。這個實現的關鍵之處在于我們預先給引擎留出了位置!我們不必因為對引擎的規則的頻頻變更而制造相當多的車身,而是盡可能地沿用和改良現有的車身。
說到這里,想說一說OO設計的一個誤區。
學
習OO語言的時候,為了能夠說明“繼承”(或者說“is-a”)這個概念,教科書上經常用實際生活中的例子來解釋。比如汽車是車,電車是車,F1賽車是汽
車,所以車是汽車、電車、F1賽車的上層抽象。這個例子并沒有錯。問題是,這樣的例子過于“形象”了!如果OO設計直接就可以將現實生活中的概念引用過
來,那也就不需要什么軟件工程師了!OO設計的關鍵概念是抽象。如果沒有抽象,那所有的軟件工程師的努力都是徒勞的。因為如果沒有抽象,我們只能去構造世
界中每一個對象。上面這個例子中,我們應該看到“引擎”這個抽象的存在,因為車隊的工程師們為它預留了位置,為它制定了設計規范。
上面這個設計也
實現了后面要說的DIP(依賴倒置原則)。但是請記住,OCP是OO設計原則中高層次的原則,其余的原則對OCP提供了不同程度的支持。為了實現OCP,
我們會自覺或者不自覺地用到其它原則或是諸如Bridge、Decorator等設計模式。然而,對于一個應用系統而言,實現OCP并不是設計目的,我們
所希望的只是一個穩定的架構。所以對OCP的追求也應該適可而止,不要陷入過渡設計。正如Martin本人所說:“No significant
program can be 100% closed.”“Closure not complete but strategic”
Liskov替換原則—— LSP?
子類型必須能夠替換它的基類型
原則
主要針對繼承的設計原則
所有派生類的行為功能必須和客戶程序對其基類所期望的保持一致。
派生類必須滿足基類和客戶程序的約定
IS-A是關于行為方式的,依賴客戶程序的調用方式
?
重構
Extract Supper Class
?
實例
依賴倒置原則—— DIP?
a:高層模塊不應依賴于底層模塊,兩者都應該依賴于抽象
b:抽象不應該依賴于細節,細節應該依賴于抽象
?
原則
如何解釋倒置
高層依賴底層,重用變得困難,而最經常重用的就是framework和各個獨立的功能組件
高層依賴底層,底層的改動直接反饋到高層,形成依賴的傳遞
面向接口的編程
?
實例
Ioc模式
DomainObject / DomianObjectDataService
?
接口隔離原則—— ISP?
使用多個專門的接口比使用單一的總接口總要好。換而言之,從一個客戶類的角度來講:一個類對另外一個類的依賴性應當是建立在最小接口上的。
原則過于臃腫的接口是對接口的污染。不應該強迫客戶依賴于它們不用的方法。
My object-oriented umbrella(摘自Design Patterns Explained)
Let me tell you about my great umbrella. It is large enough to get
into! In fact, three or four other people can get in it with me. While
we are in it, staying out of the rain, I can move it from one place to
another. It has a stereo system to keep me entertained while I stay
dry. Amazingly enough, it can also condition the air to make it warmer
or colder. It is one cool umbrella.
My umbrella is convenient. It sits there waiting for me. It has
wheels on it so that I do not have to carry it around. I don't even
have to push it because it can propel itself. Sometimes, I will open
the top of my umbrella to let in the sun. (Why I am using my umbrella
when it is sunny outside is beyond me!)
In Seattle, there are hundreds of thousands of these umbrellas in all kinds of colors. Most people call them cars.
實現方法:
1、?使用委托分離接口
2、?使用多重繼承分離接口
想到一個朋友說的話:所有的接口都只有一個方法,具體的類根據自己需要什么方法去實現接口
posted on 2006-03-17 10:00
混沌中立 閱讀(442)
評論(0) 編輯 收藏