設計模式七大原則

沿辰ᓂ發表於2020-10-01

一、設計模式的目的

編寫軟體過程中,程式設計師面臨著來自 耦合性,內聚性以及可維護性,可擴充套件性,重用性,靈活性 等多方面的挑戰,設計模式是為了讓程式(軟體),具有更好

  1. 程式碼重用性 (即:相同功能的程式碼,不用多次編寫)
  2. 可讀性 (即:程式設計規範性, 便於其他程式設計師的閱讀和理解)
  3. 可擴充套件性 (即:當需要增加新的功能時,非常的方便,稱為可維護)
  4. 可靠性 (即:當我們增加新的功能後,對原來的功能沒有影響)
  5. 使程式呈現高內聚,低耦合的特性

二、設計模式七大原則

設計模式原則,其實就是程式設計師在程式設計時,應當遵守的原則,也是各種設計模式的基礎(即:設計模式為什麼這樣設計的依據)

1. 單一職責原則

基本介紹:
對類來說的,即一個類應該只負責一項職責。如類A負責兩個不同職責:職責1,職責2。當職責1需求變更而改變A時,可能造成職責2執行錯誤,所以需要將類A的粒度分解為 A1,A2。

應用例項:交通工具案例
方案1 [分析說明]

package com.lhc.principle.singleresponsibility;

public class SingleResponsibility {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Vehicle vehicle = new Vehicle();
		vehicle.run("摩托車");
		vehicle.run("汽車");
		vehicle.run("飛機");
	}

}

//1.違反單一職責原則
//解決方案:根據交通工具執行方法不同,分解成不同類即可
class Vehicle{
	public void run(String vehicle) {
		System.out.println(vehicle + "在公路上執行...");
	}
}

方案2 [分析說明]

package com.lhc.principle.singleresponsibility;

public class SingleResponsibility2 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		RoadVehicle roadVehicle = new RoadVehicle();
		roadVehicle.run("摩托車");
		roadVehicle.run("汽車");
		AirVehicle airVehicle = new AirVehicle();
		airVehicle.run("飛機");
	}

}

//遵守單一職責原則
//改動很大,即將類分解,同時修改客戶端
//解決方案,直接修改Vehicle類,改動的程式碼會比較少
class RoadVehicle{
	public void run(String vehicle) {
		System.out.println(vehicle + "公路執行");
	}  
}
class AirVehicle{
	public void run(String vehicle) {
		System.out.println(vehicle + "空中執行");
	}  
}

方案3 [分析說明]

package com.lhc.principle.singleresponsibility;

public class SingleResponsibility3 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Vehicle2 vehicle2 = new Vehicle2();
		vehicle2.run("摩托車");
		vehicle2.run("汽車");
		vehicle2.runAir("飛機");
	}
}

//這種方法沒有對原來的類做大的修改,只是增加了方法
//
class Vehicle2{
	public void run(String vehicle) {
		System.out.println(vehicle + "在公路上執行...");
	}
	
	public void runAir(String vehicle) {
		System.out.println(vehicle + "在空中執行...");
	}
}

單一職責原則注意事項和細節:

  1. 降低類的複雜度,一個類只負責一項職責。
  2. 提高類的可讀性,可維護性
  3. 降低變更引起的風險
  4. 通常情況下,我們應當遵守單一職責原則,只有邏輯足夠簡單,才可以在程式碼級違反單一職責原則;只有類中方法數量足夠少,可以在方法級別保持單一職責原則

2.介面隔離原則
基本介紹:

  1. 客戶端不應該依賴它不需要的介面,即一個類對另一個類的依賴應該建立在最小的介面上

  2. 先看一張圖:
    在這裡插入圖片描述

  3. 類A通過介面Interface1依賴類B,類C通過介面Interface1依賴類D,如果介面Interface1對於類A和類C來說不是最小介面,那麼類B和類D必須去實現他們不需要的方法。

  4. 按隔離原則應當這樣處理:將介面Interface1拆分為獨立的幾個介面,類A和類C分別與他們需要的介面建立依賴關係。也就是採用介面隔離原則。

應用例項:
未使用介面隔離的程式碼:

package com.lhc.principle.segregation;

public class Segregation1 {

	public static void main(String[] args) {

	}

}

interface Interface1{
	void operation1();
	void operation2();
	void operation3();
	void operation4();
	void operation5();
}

class B implements Interface1{
	public void operation1() {
		System.out.println("B 實現了 operation1");
	}
	public void operation2() {
		System.out.println("B 實現了 operation2");
	}
	public void operation3() {
		System.out.println("B 實現了 operation3");
	}
	public void operation4() {
		System.out.println("B 實現了 operation4");
	}
	public void operation5() {
		System.out.println("B 實現了 operation5");
	}
}

class D implements Interface1{
	public void operation1() {
		System.out.println("D 實現了 operation1");
	}
	public void operation2() {
		System.out.println("D 實現了 operation2");
	}
	public void operation3() {
		System.out.println("D 實現了 operation3");
	}
	public void operation4() {
		System.out.println("D 實現了 operation4");
	}
	public void operation5() {
		System.out.println("D 實現了 operation5");
	}
}

class A{
	public void depend1(Interface1 i) {
		i.operation1();
	}
	public void depend2(Interface1 i) {
		i.operation2();
	}
	public void depend3(Interface1 i) {
		i.operation3();
	}
}

class C{
	public void depend1(Interface1 i) {
		i.operation1();
	}
	public void depend4(Interface1 i) {
		i.operation4();
	}
	public void depend5(Interface1 i) {
		i.operation5();
	}
}

類A通過介面Interface1依賴類B, 類C通過介面Interface1依賴類D。
在這裡插入圖片描述

使用介面隔離後的程式碼:

package com.lhc.principle.segregation1;

public class Segregation1 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 使用一把
		A a = new A();
		a.depend1(new B()); // A類通過介面去依賴B類
		a.depend2(new B());
		a.depend3(new B());

		C c = new C();

		c.depend1(new D()); // C類通過介面去依賴(使用)D類
		c.depend4(new D());
		c.depend5(new D());

	}

}

// 介面1
interface Interface1 {
	void operation1();

}

// 介面2
interface Interface2 {
	void operation2();

	void operation3();
}

// 介面3
interface Interface3 {
	void operation4();

	void operation5();
}

class B implements Interface1, Interface2 {
	public void operation1() {
		System.out.println("B 實現了 operation1");
	}

	public void operation2() {
		System.out.println("B 實現了 operation2");
	}

	public void operation3() {
		System.out.println("B 實現了 operation3");
	}

}

class D implements Interface1, Interface3 {
	public void operation1() {
		System.out.println("D 實現了 operation1");
	}

	public void operation4() {
		System.out.println("D 實現了 operation4");
	}

	public void operation5() {
		System.out.println("D 實現了 operation5");
	}
}

class A { // A 類通過介面Interface1,Interface2 依賴(使用) B類,但是隻會用到1,2,3方法
	public void depend1(Interface1 i) {
		i.operation1();
	}

	public void depend2(Interface2 i) {
		i.operation2();
	}

	public void depend3(Interface2 i) {
		i.operation3();
	}
}

class C { // C 類通過介面Interface1,Interface3 依賴(使用) D類,但是隻會用到1,4,5方法
	public void depend1(Interface1 i) {
		i.operation1();
	}

	public void depend4(Interface3 i) {
		i.operation4();
	}

	public void depend5(Interface3 i) {
		i.operation5();
	}
}

3.依賴倒轉原則
基本介紹:

  1. 高層模組不應該依賴低層模組,二者都應該依賴其抽象
  2. 抽象不應該依賴細節,細節應該依賴抽象
  3. 依賴倒轉(倒置)的中心思想是面向介面程式設計
  4. 依賴倒轉原則是基於這樣的設計理念:相對於細節的多變性,抽象的東西要穩定的多。以抽象為基礎搭建的架構比以細節為基礎的架構要穩定的多。在java中,抽象指的是介面或抽象類,細節就是具體的實現類
  5. 使用介面或抽象類的目的是制定好規範,而不涉及任何具體的操作,把展現細節的任務交給他們的實現類去完成

依賴倒轉原則的注意事項和細節

  1. 低層模組儘量都要有抽象類或介面,或者兩者都有,程式穩定性更好.
  2. 變數的宣告型別儘量是抽象類或介面, 這樣我們的變數引用和實際物件間,就存在
    一個緩衝層,利於程式擴充套件和優化
  3. 繼承時遵循里氏替換原則

4.里氏替換原則
基本介紹:

  1. 里氏替換原則(Liskov Substitution Principle)在1988年,由麻省理工學院的以為姓裡的女士提出的。
  2. 如果對每個型別為T1的物件o1,都有型別為T2的物件o2,使得以T1定義的所有程式P在所有的物件o1都代換成o2時,程式P的行為沒有發生變化,那麼型別T2是型別T1的子型別。換句話說,所有引用基類的地方必須能透明地使用其子類的物件。
  3. 在使用繼承時,遵循里氏替換原則,在子類中儘量不要重寫父類的方法
  4. 里氏替換原則告訴我們,繼承實際上讓兩個類耦合性增強了,在適當的情況下,可以通過聚合,組合,依賴 來解決問題。.

5.開閉原則
基本介紹:

  1. 開閉原則(Open Closed Principle)是程式設計中最基礎、最重要的設計原則
  2. 一個軟體實體如類,模組和函式應該對擴充套件開放(對提供方),對修改關閉(對使用方)。用抽象構建框架,用實現擴充套件細節。
  3. 當軟體需要變化時,儘量通過擴充套件軟體實體的行為來實現變化,而不是通過修改已有的程式碼來實現變化。
  4. 程式設計中遵循其它原則,以及使用設計模式的目的就是遵循開閉原則。

6.迪米特法則
基本介紹:

  1. 一個物件應該對其他物件保持最少的瞭解
  2. 類與類關係越密切,耦合度越大
  3. 迪米特法則(Demeter Principle)又叫最少知道原則,即一個類對自己依賴的類知道的越少越好。也就是說,對於被依賴的類不管多麼複雜,都儘量將邏輯封裝在類的內部。對外除了提供的public 方法,不對外洩露任何資訊
  4. 迪米特法則還有個更簡單的定義:只與直接的朋友通訊
  5. 直接的朋友:每個物件都會與其他物件有耦合關係,只要兩個物件之間有耦合關係,我們就說這兩個物件之間是朋友關係。耦合的方式很多,依賴,關聯,組合,聚合等。其中,我們稱出現成員變數,方法引數,方法返回值中的類為直接的朋友,而出現在區域性變數中的類不是直接的朋友。也就是說,陌生的類最好不要以區域性變數的形式出現在類的內部。

迪米特法則注意事項和細節:

  1. 迪米特法則的核心是降低類之間的耦合
  2. 但是注意:由於每個類都減少了不必要的依賴,因此迪米特法則只是要求降低類間(物件間)耦合關係, 並不是要求完全沒有依賴關係

7.合成複用原則
基本介紹:
原則是儘量使用合成/聚合的方式,而不是使用繼承

設計原則核心思想

  1. 找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的程式碼混在一起。
  2. 針對介面程式設計,而不是針對實現程式設計。
  3. 為了互動物件之間的鬆耦合設計而努力

相關文章