上篇說到設計模式的精髓是原則和思想,這篇文章就詳細介紹一下設計模式的原則。 一、單一職責原則 定義:就一個類而言,應該僅有一個引起它變化的原因。 人都說,這個原則太普通了,和名字一樣簡單。不是說大道至簡嘛,這個原則在程式設計中所占的份量還是很重的。 一個類涉及的多項功能,如果其中一個功能發生改變需要 ...
上篇說到設計模式的精髓是原則和思想,這篇文章就詳細介紹一下設計模式的原則。
一、單一職責原則
定義:就一個類而言,應該僅有一個引起它變化的原因。
人都說,這個原則太普通了,和名字一樣簡單。不是說大道至簡嘛,這個原則在程式設計中所占的份量還是很重的。
一個類涉及的多項功能,如果其中一個功能發生改變需要修改,同類中就有可能會影響到其他已經實現好的功能。為了避免此類情況,可以將實現的功能單獨出類來。當修改功能時是修改不同的類,就不會使其他類出現問題。
話雖如此,在實際應用中往往會出現讓人始料未及的情況。比如一個類實現了一個功能,在項目初期是符合單一職責原則的。但隨著項目的開展,需求的改變,這個功能可能分化成兩個或者多個功能(職責擴散),而部分功能代碼已經完成,我們該如何呢?這是個現實的問題,是選擇重構代碼,還是在基礎代碼上進行修改(會違背單一職責原則),這就得看程式員們怎麼把握這個度了。
二、開放-封閉原則
定義:軟體實體(類、模塊、方法等)應該可以擴展,但不可以修改。
對於理解這個原則,實際上只要搞清楚開放的是什麼,封閉的是什麼。
在實際開發中,我們的需求並不是一塵不變的。這就極大的挑戰了在項目初期的設計,對後期的維護與需求的增加難度具有重大意義。
然而這個原則取十分模糊。如果上司要求你設計個項目結構,要遵循開閉原則,你就會感覺仿佛什麼都沒說,卻又好像什麼都說了。筆者認為,如果很好的遵循了其他幾個原則,開閉原則也就在不知不覺中實現。
三、里氏代換原則
定義:子類型必須能夠替換掉它們的父類型。
面向對象編程中,繼承是非常重要的概念。里氏這個命名是因為這個原則是Barbara Liskov女士1988年發表的。名字並不重要,重要的是思想。
簡而言之,這個原則就是在程式設計的世界里,“爸爸能做的事情兒子一定能做”。在程式中,把所有的父類替換成子類並不影響程式的正常運行。只有這樣,父類才能被真正復用,而子類也能夠在父類的基礎上增加新的行為。
舉個例子:
Parent parent = new elderSon(); parent.mathod1(); parent.mathod2(); parent.mathod3();
如果需求改變了,程式擴展,只需要修改實例化時的子對象即可,如
Parent parent = new youngerSon();//只修改此處 parent.mathod1(); parent.mathod2(); parent.mathod3();
程式單元不會起任何變化。
四、依賴倒轉原則
定義:高層模塊不應該依賴底層模塊。兩個都應該依賴抽象。抽象不應該依賴細節,細節應該依賴抽象。
實際項目中,為了使常用的代碼得到復用,會把常用的方法函數寫成程式庫。在新項目時,就可以調用底層程式庫來實現簡化程式的目的。如此做,便會出現高層模塊依賴底層模塊的問題。
而由於需求的不同,會導致底層的實現有所差異,比如資料庫連接,不同的資料庫有不同的方法連接。這樣在維護或拓展功能帶來隱患。如果遵循依賴倒轉原則便不會出現這種狀況。如圖:
設計成
如此便誰也不依賴誰,只有約定的介面,程式便可靈活的修改或復用。
五、迪米特法則(最少知識原則)
定義:如果兩個類不必彼此直接通信,那麼這兩個類就不應當發生直接的相互作用。如果其中一類需要調用另一個類的某一個方法,可以通過第三者轉發這個調用。
一個對象對其他對象瞭解的最少,類的復用性才可以越高。迪米特法則的核心便是解耦合,只關心公開的方法,只調用公開的方法,其他的我不關心。那句話叫“不要和陌生人說話”。
舉個例子:
class A { public void doSomething() { System.out.println("do something over."); } } class B { private A a = new A(); public A getA() { return a; } } class C { private B b = new B(); public void doSomething() { A a = b.getA(); a.doSomething(); } } public class Client { public static void main(String[] args) { new C().doSomething(); } }
上面的設計便違反了迪米特法則。類C和類A並不是朋友(成員變數),在類C方法中出現類A是不合適的。應改為:
class A { public void doSomething() { System.out.println("do something over."); } } class B { private A a = new A(); public void doSomething() { a.doSomething(); } } class C { private B b = new B(); public void doSomething() { b.doSomething(); } } public class Client { public static void main(String[] args) { new C().doSomething(); } }
如此,便符合了原則。
六、介面隔離原則
定義:客戶端不應該依賴它不需要的介面;類間的依賴關係應該建立在最小的介面上。
俗話說,“狗拿耗子,多管閑事”。每一個介面都應該承擔一種相對獨立的角色,應該為客戶端提供獨立功能的小介面,不是總介面。
網上看到兩張圖片,很好的闡釋了這一原則