Java設計模式-六大設計原則

Java設計模式的設計原則

單一職責原則

單一職責原則的英文名稱是Single Responsibility Principle,簡稱SRP。

1. 定義

單一職責原則的定義:應該有且僅有一個原因引起類的變更。

單一職責原則要求類的設計、接口的設計、方法的設計都是滿足單一職責原則,就是要保證類、接口、方法只做一件事或者是同一類型、同一職責的操作。

2. 優點

  • 類的複雜度降低,實現什麼職責都有清晰明確的定義
  • 可讀性提高,複雜性降低,自然就可以提高可讀性
  • 可維護性提高,可讀性提高,自然可維護性也提高
  • 變更引起的風險降低。

3. 設計

在方法的設計時,要保證我們設計的方法只做一件事情。
在接口設計時,也要在設計的時候做到單一職責,這樣可以降低維護的成本。
在設計接口的實現類時,需要考慮實際的應用場景。如果把單一職責強加到實現類上,會引起類的數量的劇增,從而極大的增加系統的複雜度。

里氏替換原則

里氏替換原則的英文名稱是Liskov Substitution Principle, 簡稱LSP。
里氏替換原則爲了最大的發揮繼承的優勢同時又降低繼承的弊端。

1. 定義

1.1 繼承

繼承的優點

  • 代碼共享,減少創建類的工作量
  • 提高代碼的重用性
  • 子類可以形似父類,但是又區別於父類
  • 提高代碼的可拓展性
  • 提高產品和項目的開放性

繼承的缺點

  • 繼承是可入侵的。只要是繼承就必須讓子類擁有父類的全部屬性和方法
  • 減低代碼的靈活性。子類必須擁有父類的屬性和方法,豐富了子類的同時也給子類增加了父類的限制
  • 增強了耦合性。當父類的常量、變量和方法被修改時,需要考慮子類的修改。

1.2 里氏替換原則的定義

里氏替換原則的定義:所有引用基類的地方必須能透明地使用其子類的對象。

通俗來講,就是隻要父類能出現的地方子類就可以出現,但是子類能出現的地方,父類未必能夠出現。

2. 規則約束

2.1 子類必須完全實現父類的方法

我們在設計時,通常會定義一個接口或是抽象類,然後通過編碼實現,然後調用類則直接傳入接口或者抽象類作爲參數,這樣就是一個符合里氏替換原則的設計。
同樣,在類中調用其他類時務必使用父類或接口,如果不能使用父類或接口,則說明類的設計時不符合里氏替換原則的。
如果子類不能完整地實現父類的方法,或者實現父類的某些方法在子類中發生的變異,那麼建議斷開繼承關係,採用依賴、聚集、組合等關係替代。

2.2 子類可以有自己的個性

由於里氏替換原則規定,父類出現的地方子類就可以出現,但是子類出現的地方父類未必可以出現。因此,子類完全可以擁有自己的屬性和方法,以豐富自身的功能。

2.3 覆蓋或實現父類的方法時,輸入參數可以被放大

子類中方法的前置條件必須與超類中被覆寫的方法的前置條件相同或更寬鬆。

2.4 覆寫或實現父類的方法時,輸出結果可以被縮小

依賴倒置原則

依賴倒置原則的英文名稱是:Dependence Inversion Principle, DIP

1. 定義

依賴倒置原則:
1. 高層的模塊不應該依賴於底層模塊,兩者都應該依賴其抽象
2. 抽象不應該依賴細節
3. 細節應該依賴抽象

依賴倒置原則體現在Java語言中的表現是:
+ 模塊間的依賴通過抽象產生,實現類之間不發生直接的依賴關係,其依賴關係是通過接口或抽象類產生的
+ 接口或抽象類不依賴於實現類;
+ 實現類依賴接口或抽象類。

依賴倒置原則也就是“面向接口編程”, 即OOD(Object-Oriented Design, 面向對象設計)的精髓之一。

2. 實例

我們先通過一個例子來說明爲什麼要用依賴倒置原則。
故事背景:小明最近剛剛拿了駕照,準備開車上道。一個新手司機要去駕駛一輛經典款大衆甲殼蟲。
我們先看一個UML圖如何實現司機駕駛經典甲殼蟲的。

但是,小明好不容易拿到了駕照,家裏的車庫裏又不只是有甲殼蟲這麼一款車,他家裏還有奔馳、寶馬、奧迪等等,作爲一個有尊嚴的馬路殺手,怎麼能只開這一款車那,於是我們之前做的設計就不能適用。
我們需要從新設計,讓小明這個馬路殺手可以去駕駛各種各樣的小汽車。

我們通過接口的方式就可以實現了讓司機駕駛多種車,只需要在駕駛不同的車型時傳入不同的實現類就可以了。
這樣我們就實現了接口或抽象不依賴實現類,而且依賴關係也是通過接口傳遞的。

3. 依賴的三種寫法

無論以怎樣的方式實現依賴,對象的依賴關係都是通過抽象傳遞的。
我們將通過以上的例子來說明如何實現以下三種依賴方式。

2.1 構造函數傳遞依賴對象

    //司機接口
    public interface IDriver{
        public void drive();
    }

    //司機實現類
    public class Driver implements IDriver{
        private ICar car;

        public Driver(ICar car){
            this.car = car;
        }

        public void drive(){
            this.car.run();
        }
    }

2.2 Setter方法傳遞依賴對象

    //司機接口
    public interface IDriver{
        public void drive();
    }

    //司機實現類
    public class Driver implements IDriver{
        private ICar car;

        public void setCar(ICar car){
            this.car = car;
        }

        public void drive(){
            this.car.run();
        }
    }

2.3 接口聲明依賴對象

基於接口的方法就是我們在第二小節中實例中使用的方法,把接口作爲參數傳遞給drive方法。

接口隔離原則

接口隔離原則的英文名稱是:Interface Segregation Principle,簡稱ISP。

1. 定義

接口隔離原則的定義可以概括爲:建立單一接口, 即接口不要過於龐大,應當儘量喜歡。接口的設計應該保證其接口內功能相對的少。

2. 約束

接口隔離原則是對接口進行規範約束,主要有一下四個方面:

  • 接口要儘量小:本條約束主要是指希望程序中不會出現臃腫的接口,但是”小”的同時要保證接口不違反單一職責原則。
  • 接口要高內聚:高內聚就是指要提高接口、類、模塊的處理能力,減少對外部的交互。
  • 定製服務:系統設計過程不同模塊中會或多或少存在耦合,一旦出現耦合就需要提供相互訪問的接口。因此我們需要在給訪問者提供接口是提供定製服務,也就是隻提供訪問者需要的方法,
  • 接口設計是有限度的:接口的設計粒度越小,系統越靈活。但是,靈活的同時也會帶來結構的複雜化,開發難度增加,導致可維護性降低。因此設計過程中要根據業務需求和性能需求來判斷這個”度”。

3. 實踐規則

  • 一個接口只服務於一個子模塊或者業務邏輯
  • 通過業務邏輯壓縮接口中public方法
  • 已經被污染的接口,儘量去修改,若變更的風險較大,則採用適配器模式進行轉換處理
  • 瞭解環境,拒絕盲從

迪米特法則

迪米特法則的英文名稱是:Law of Demeter, LoD。迪米特法則也叫最少知識原則(Leask Knowledge Principle, LKP).

1. 定義

迪米特法則:一個對象對其他對象有最少的瞭解。即:一個類要對自己需要耦合或調用的類知道得最少。

粗俗來講:調用者在調用其他的接口或者是類時,應當只知道被調用者提供了那些public方法。保證調用者對別調用者最少的訪問。

2. 約定

迪米特法則的核心觀念就是類間解耦,弱耦合,從而提高類的複用率。但是,在使用迪米特法則的時候尤其要注意”度”的問題。與接口隔離原則一樣,當耦合度降低的時候,也會導致系統的複雜度增加。在實際的項目中應當權衡利弊,既要保證項目結構清晰,也要做到高內聚、低耦合。

開閉原則

開閉原則的核心就是對拓展開放,對修改關閉。 

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