1. 程式人生 > >java設計模式系列---設計原則

java設計模式系列---設計原則

java設計模式系列—設計原則

本文作為java設計模式系列開篇,首先介紹下設計模式的七大設計原則。
1. 開閉原則
1.1 定義
一個軟體實體如類、模組和函式應該對擴充套件開放,對修改關閉。
1.2 核心
(1)對原有程式碼修改關閉
(2)對新程式碼的擴充套件開放
(3)其他原則都是為開閉原則服務的
1.3 開閉原則的重要性
為什麼使用開閉原則?
對測試的影響
可提高複用性
可提高可維護性
面向物件開發的要求
1.4 如何使用開閉原則
找出可變化的因素—>提煉穩定的介面—>抽象具體實現,完成具體功能
2. 單一職責原則
2.1 定義


Single Responsibility Principle SRP原則
單一職責原則指的是應該有且僅有一個原因引起類的變更。
說到單一職責原則,很多人都會不屑一顧。因為它太簡單了。稍有經驗的程式設計師即使從來沒有讀過設計模式、從來沒有聽說過單一職責原則,在設計軟體時也會自覺的遵守這一重要原則,因為這是常識。在軟體程式設計中,誰也不希望因為修改了一個功能導致其他的功能發生故障。而避免出現這一問題的方法便是遵循單一職責原則。雖然單一職責原則如此簡單,並且被認為是常識,但是即便是經驗豐富的程式設計師寫出的程式,也會有違背這一原則的程式碼存在。為什麼會出現這種現象呢?因為有職責擴散。所謂職責擴散,就是因為某種原因,職責P被分化為粒度更細的職責P1和P2。
2.2 遵循單一職責原的優點

(1)可以降低類的複雜度,一個類只負責一項職責,其邏輯肯定要比負責多項職責簡單的多;
(2)提高類的可讀性,提高系統的可維護性;
(3)變更引起的風險降低,變更是必然的,如果單一職責原則遵守的好,當修改一個功能時,可以顯著降低對其他功能的影響。
需要說明的一點是單一職責原則不只是面向物件程式設計思想所特有的,只要是模組化的程式設計,都需要遵循這一重要原則。
3. 裡式替換原則
3.1 定義
里氏置換原則(Liskov Substitution Principle),簡稱LSP。
所有引用基類的地方必須能透明地使用其子類的物件,通俗的來講就是父類能出現的地方子類就可以出現,但是反過來就不行了。子類可以擴充套件父類的功能,但不能改變父類原有的功能。
3.2 裡式替換四層含義

只有當子類可以替換掉父類,軟體單位的功能不受影響時,父類才能真正被複用,而子類也能夠在父類的基礎上增加新的行為,正是有里氏代換原則,使得繼承複用成為了可能。正是由於子型別的可替換性才使得使用父類型別的模組在無需修改的情況下就可以擴充套件,不然還談什麼擴充套件開放,修改關閉呢。
里氏替換原則通俗的來講就是:子類可以擴充套件父類的功能,但不能改變父類原有的功能。
裡式替換四層含義:
(1)子類可以實現父的抽象方法,但不能覆寫父類的非抽象方法。 父類中凡是已經實現好的方法(相對於抽象方法而言),實際上是在設定一系列的規範和契約,雖然它不強制要求所有的子類必須遵從這些契約,但是如果子類對這些非抽象方法任意修改,就會對整個繼承體系造成破壞。
(2)子類中可以增加自己特有的方法。
(3)覆寫或實現父類的方法時,輸入引數可以被放大。(覆寫指的覆寫一個正常方法並重寫,是實現指的是實現介面或者抽象方法)
(4)覆寫或實現父類的方法時輸出結果可以被縮小(若放大,還能用子類替換父類嗎?)
4. 依賴倒置原則
4.1 定義
Dependence Inversion Principle DIP原則,高層模組不應該依賴低層模組,抽象不應該依賴細節,細節依賴抽象。即針對介面程式設計,不要針對實現程式設計。
4.2 依賴倒置原則在java中的實現
在Java中的表現為:面向介面程式設計 OOP
(1)模組間的依賴通過抽象發生,實現類間不發生直接的依賴關係,其依賴關係通過介面或者抽象類產生;
(2)介面或抽象類不依賴於實現類
(3)實現類依賴於介面或者抽象類
依賴倒置原則可以減少類之間的耦合性,提高系統的穩定性;降低並行開發引起的風險。
要並行開發就要解決模組間的依賴關係,依賴倒置原則正好解決這個問題。
4.3 依賴的三種寫法
依賴的三種寫法:依賴是可以傳遞的,只要做到抽象依賴,即使是多層的依賴也沒關係。
(1)建構函式傳遞依賴物件
(2)Setter方法傳遞依賴物件
(3)介面方法中傳入依賴物件
4.4 依賴倒置原則最佳實踐
(1)每個類儘量都有介面或者抽象類
(2)變數的表面型別儘量是介面或者抽象類
(3)不從具體類派生類
(4)儘量不覆寫基類的方法,只實現
5. 介面隔離原則
5.1 定義
Interface Segregation Principle ISP原則,建立單一介面,不要建立龐大臃腫的介面,儘量細化介面,介面中的方法儘量少。也就是說,我們要為各個類建立專用的介面,而不要試圖去建立一個很龐大的介面供所有依賴它的類去呼叫。在程式設計中,依賴幾個專用的介面要比依賴一個綜合的介面更靈活。介面是設計是對外部設定的“契約”,通過分散定義多個介面,可以預防外來變更的擴散,提高系統的靈活性和可維護性。
5.2 使用介面隔離原則的一些規範
在使用介面隔離原則的時候需要有一些規範:
(1)介面儘量小,介面儘量小主要是為了保證一個介面只服務一個子模組或者業務邏輯
(2)介面高內聚,介面高內聚是對內高度依賴,對外儘可能隔離。即一個介面內部的宣告的方法相互之間都與某一個子模組相關,且是這個子模組必須的。
(3)介面設計是有限度的
6. 組合/複用原則
6.1 定義
組合/聚合是加法,繼承是乘法,所以儘量要儘量的使用合成和聚合,而不是繼承關係達到複用的目的
該原則就是在一個新的物件裡面使用一些已有的物件,使之成為新物件的一部分:新的物件通過向這些物件的委派達到複用已有功能的目的。
其實這裡最終要的地方就是區分“has-a”和“is-a”的區別。相對於合成和聚合,
繼承的缺點在於:父類的方法全部暴露給子類。父類如果發生變化,子類也得發生變化。聚合的複用的時候就對另外的類依賴的比較的少。。
6.2 合成/聚合複用優缺點
(1)優點
新物件存取成分物件的唯一方法是通過成分物件的介面;
這種複用是黑箱複用,因為成分物件的內部細節是新物件所看不見的;
這種複用支援包裝;
這種複用所需的依賴較少;
每一個新的類可以將焦點集中在一個任務上;
這種複用可以在執行時動態進行,新物件可以使用合成/聚合關係將新的責任委派到合適的物件。
(2)缺點
通過這種方式複用建造的系統會有較多的物件需要管理。
6.3 繼承複用優缺點
① 優點:
新的實現較為容易,因為基類的大部分功能可以通過繼承關係自動進入派生類;
修改或擴充套件繼承而來的實現較為容易。
② 缺點:
繼承複用破壞包裝,因為繼承將基類的實現細節暴露給派生類,這種複用也稱為白箱複用;如果基類的實現發生改變,那麼派生類的實現也不得不發生改變;從基類繼承而來的實現是靜態的,不可能在執行時發生改變,不夠靈活。
7. 迪米特法則
Law of Demter LoD
也稱為最少知識原則:Least Knowledge Principle LKP
描述的是,一個物件應該對其他物件有最少的瞭解,一個類只需要知道自己需要耦合或者呼叫類的public方法即可。
迪米特法則其根本思想,是強調了類之間的鬆耦合,類之間的耦合越弱,越有利於複用,一個處在弱耦合的類被修改,不會對有關係的類造成影響,也就是說,資訊的隱藏促進了軟體的複用。
自從我們接觸程式設計開始,就知道了軟體程式設計的總的原則:低耦合,高內聚。無論是面向過程程式設計還是面向物件程式設計,只有使各個模組之間的耦合儘量的低,才能提高程式碼的複用率。低耦合的優點不言而喻,但是怎麼樣程式設計才能做到低耦合呢?那正是迪米特法則要去完成的。
迪米特法則又叫最少知道原則,最早是在1987年由美國Northeastern University的Ian Holland提出。通俗的來講,就是一個類對自己依賴的類知道的越少越好。也就是說,對於被依賴的類來說,無論邏輯多麼複雜,都儘量地的將邏輯封裝在類的內部,對外除了提供的public方法,不對外洩漏任何資訊。迪米特法則還有一個更簡單的定義:只與直接的朋友通訊。首先來解釋一下什麼是直接的朋友:每個物件都會與其他物件有耦合關係,只要兩個物件之間有耦合關係,我們就說這兩個物件之間是朋友關係。耦合的方式很多,依賴、關聯、組合、聚合等。其中,我們稱出現成員變數、方法引數、方法返回值中的類為直接的朋友,而出現在區域性變數中的類則不是直接的朋友。也就是說,陌生的類最好不要作為區域性變數的形式出現在類的內部。
一句話總結就是:一個物件應該對其他物件保持最少的瞭解