Java面向對象設計的六大原則

這是設計模式系列開篇的第一篇文章。也是我學習設計模式過程當中的總結。這篇文章主要講的是面向對象設計中,咱們應該遵循的六大原則。只有掌握了這些原則,咱們才能更好的理解設計模式。咱們接下來要介紹如下6個內容。編程

  • 單一職責原則——SRP設計模式

  • 開閉原則——OCP框架

  • 裏式替換原則——LSPide

  • 依賴倒置原則——DIP函數

  • 接口隔離原則——ISP學習

  • 迪米特原則——LODspa

單一職責原則

單一職責原則的定義是就一個類而言,應該僅有一個引發他變化的緣由。也就是說一個類應該只負責一件事情。若是一個類負責了方法M1,方法M2兩個不一樣的事情,當M1方法發生變化的時候,咱們須要修改這個類的M1方法,可是這個時候就有可能致使M2方法不能工做。這個不是咱們期待的,可是因爲這種設計卻頗有可能發生。因此這個時候,咱們須要把M1方法,M2方法單獨分離成兩個類。讓每一個類只專心處理本身的方法。設計

單一職責原則的好處以下:code

能夠下降類的複雜度,一個類只負責一項職責,這樣邏輯也簡單不少 提升類的可讀性,和系統的維護性,由於不會有其餘奇怪的方法來干擾咱們理解這個類的含義 當發生變化的時候,能將變化的影響降到最小,由於只會在這個類中作出修改。對象

開閉原則

開閉原則和單一職責原則同樣,是很是基礎並且通常是常識的原則。開閉原則的定義是軟件中的對象(類,模塊,函數等)應該對於擴展是開放的,可是對於修改是關閉的。

當需求發生改變的時候,咱們須要對代碼進行修改,這個時候咱們應該儘可能去擴展原來的代碼,而不是去修改原來的代碼,由於這樣可能會引發更多的問題。

這個準則和單一職責原則同樣,是一個你們都這樣去認爲可是又沒規定具體該如何去作的一種原則。

開閉原則咱們能夠用一種方式來確保他,咱們用抽象去構建框架,用實現擴展細節。這樣當發生修改的時候,咱們就直接用抽象了派生一個具體類去實現修改。

里氏替換原則

里氏替換原則是一個很是有用的一個概念。他的定義

若是對每個類型爲T1的對象o1,都有類型爲T2的對象o2,使得以T1定義的全部程序P在全部對象o1都替換成o2的時候,程序P的行爲都沒有發生變化,那麼類型T2是類型T1的子類型。

這樣說有點複雜,其實有一個簡單的定義

全部引用基類的地方必須可以透明地使用其子類的對象。

里氏替換原則通俗的去講就是:子類能夠去擴展父類的功能,可是不能改變父類原有的功能。他包含如下幾層意思:

  • 子類能夠實現父類的抽象方法,可是不能覆蓋父類的非抽象方法。

  • 子類能夠增長本身獨有的方法。

  • 當子類的方法重載父類的方法時候,方法的形參要比父類的方法的輸入參數更加寬鬆。

  • 當子類的方法實現父類的抽象方法時,方法的返回值要比父類更嚴格。

里氏替換原則之因此這樣要求是由於繼承有不少缺點,他雖然是複用代碼的一種方法,但同時繼承在必定程度上違反了封裝。父類的屬性和方法對子類都是透明的,子類能夠隨意修改父類的成員。這也致使了,若是需求變動,子類對父類的方法進行一些複寫的時候,其餘的子類沒法正常工做。因此里氏替換法則被提出來。

確保程序遵循里氏替換原則能夠要求咱們的程序創建抽象,經過抽象去創建規範,而後用實現去擴展細節,這個是否是很耳熟,對,里氏替換原則和開閉原則每每是相互依存的。

依賴倒置原則

依賴倒置原則指的是一種特殊的解耦方式,使得高層次的模塊不該該依賴於低層次的模塊的實現細節的目的,依賴模塊被顛倒了。這也是一個讓人難懂的定義,他能夠簡單來講就是

高層模塊不該該依賴底層模塊,二者都應該依賴其抽象 抽象不該該依賴細節 細節應該依賴抽象

在Java 中抽象指的是接口或者抽象類,二者皆不能實例化。而細節就是實現類,也就是實現了接口或者繼承了抽象類的類。他是能夠被實例化的。高層模塊指的是調用端,底層模塊是具體的實現類。在Java中,依賴倒置原則是指模塊間的依賴是經過抽象來發生的,實現類之間不發生直接的依賴關係,其依賴關係是經過接口是來實現的。這就是俗稱的面向接口編程。

咱們下面有一個例子來說述這個問題。這個例子是工人用錘子來修理東西。咱們的代碼以下:

    

 1 public class Hammer {
 2     public String function(){
 3         return "用錘子修理東西";
 4     }
 5 }
 6  
 7 public class Worker {
 8     public void fix(Hammer hammer){
 9         System.out.println("工人" + hammer.function());
10     }
11  
12  
13     public static void main(String[] args) {
14         new Worker().fix(new Hammer());
15     }
16 }

 

 

這個是一個很簡單的例子,可是若是咱們要新增長一個功能,工人用 螺絲刀來修理東西,在這個類,咱們發現是很難作的。由於咱們Worker類依賴於一個具體的實現類Hammer。因此咱們用到面向接口編程的思想,改爲以下的代碼:

1 public interface Tools {
2     public String function();
3 }

 

而後咱們的Worker是經過這個接口來於其餘細節類進行依賴。代碼以下:

 1 public class Worker {
 2     public void fix(Tools tool){
 3         System.out.println("工人" + tool.function());
 4     }
 5  
 6  
 7     public static void main(String[] args) {
 8         new Worker().fix(new Hammer());
 9         new Worker().fix(new Screwdriver());
10  
11     }
12 }

 

咱們的Hammer類與Screwdriver類實現這個接口

public class Hammer implements Tools{
    public String function(){
        return "用錘子修理東西";
    }
}
 
public class Screwdriver implements Tools{
    @Override
    public String function() {
        return "用螺絲刀修理東西";
    }
}

 

這樣,經過面向接口編程,咱們的代碼就有了很高的擴展性,下降了代碼之間的耦合度,提升了系統的穩定性。

接口隔離原則

接口隔離原則的定義是

客戶端不該該依賴他不須要的接口

換一種說法就是類間的依賴關係應該創建在最小的接口上。這樣說好像更難懂。咱們經過一個例子來講明。咱們知道在Java中一個具體類實現了一個接口,那必然就要實現接口中的全部方法。若是咱們有一個類A和類B經過接口I來依賴,類B是對類A依賴的實現,這個接口I有5個方法。可是類A與類B只經過方法1,2,3依賴,而後類C與類D經過接口I來依賴,類D是對類C依賴的實現可是他們倒是經過方法1,4,5依賴。那麼是必在實現接口的時候,類B就要有實現他不須要的方法4和方法5 而類D就要實現他不須要的方法2,和方法3。這簡直就是一個災難的設計。

因此咱們須要對接口進行拆分,就是把接口分紅知足依賴關係的最小接口,類B與類D不須要去實現與他們無關接口方法。好比在這個例子中,咱們能夠把接口拆成3個,第一個是僅僅由方法1的接口,第二個接口是包含2,3方法的,第三個接口是包含4,5方法的。這樣,咱們的設計就知足了接口隔離原則。

以上這些設計思想用英文的第一個字母能夠組成SOLID ,知足這個5個原則的程序也被稱爲知足了SOLID準則。

迪米特原則

迪米特原則也被稱爲最小知識原則,他的定義

一個對象應該對其餘對象保持最小的瞭解。

由於類與類之間的關係越密切,耦合度越大,當一個類發生改變時,對另外一個類的影響也越大,因此這也是咱們提倡的軟件編程的總的原則:低耦合,高內聚。迪米特法則還有一個更簡單的定義

只與直接的朋友通訊。首先來解釋一下什麼是直接的朋友:每一個對象都會與其餘對象有耦合關係,只要兩個對象之間有耦合關係,咱們就說這兩個對象之間是朋友關係。耦合的方式不少,依賴、關聯、組合、聚合等。其中,咱們稱出現成員變量、方法參數、方法返回值中的類爲直接的朋友,而出如今局部變量中的類則不是直接的朋友。也就是說,陌生的類最好不要做爲局部變量的形式出如今類的內部。

這裏咱們能夠用一個現實生活中的例子來說解一下。好比咱們須要一張CD,咱們可能去音像店去問老闆有沒有咱們須要的那張CD,老闆說如今沒有,等有的時候大家來拿就好了。在這裏咱們不須要關心老闆是從哪裏,怎麼得到的那張CD,咱們只和老闆(直接朋友)溝通,至於老闆從他的朋友那裏經過何種條件獲得的CD,咱們不關心,咱們不和老闆的朋友(陌生人)進行通訊,這個就是迪米特的一個應用。說白了,就是一種中介的方式。咱們經過老闆這個中介來和真正提供CD的人發生聯繫。

總結

到這裏,面向對象的六大原則,就寫完了。咱們看出來,這些原則其實都是應對不斷改變的需求。每當需求變化的時候,咱們利用這些原則來使咱們的代碼改動量最小,並且所形成的影響也是最小的。可是咱們在看這些原則的時候,咱們會發現不少原則並無提供一種公式化的結論,而即便提供了公式化的結論的原則也只是建議去這樣作。這是由於,這些設計原則原本就是從不少實際的代碼中提取出來的,他是一個經驗化的結論。怎麼去用它,用好他,就要依靠設計者的經驗。不然一味者去使用設計原則可能會使代碼出現過分設計的狀況。大多數的原則都是經過提取出抽象和接口來實現,若是發生過分的設計,就會出現不少抽象類和接口,增長了系統的複雜度。讓原本很小的項目變得很龐大,固然這也是Java的特性(任何的小項目都會作成中型的項目)。

相關文章
相關標籤/搜索