1. 程式人生 > >淺談設計模式的六大原則

淺談設計模式的六大原則

一,單一職責原則:就一個類而言,應該僅有一個引起它變化的原因(就是實現類要責任單一)

英文--Single Responsibility Principle 

簡寫:SRP

舉個例子:

   父類:Animal

public class Animal {
	
	 void move(String animal){
		System.out.println(animal + "是主要用腳來移動的");
	}
}
測試類:
  <pre name="code" class="java">public class SRPTest {

	public static void main(String[] args) {
		Animal animal = new Animal();
		animal.move("狗");
		animal.move("貓");
		animal.move("老鼠");

	}

}
輸出:
狗是主要用腳來移動的
貓是主要用腳來移動的
老鼠是主要用腳來移動的
那麼問題來了,當你新增鳥時,打印出,鳥主要是用腳來移動的,(但好像是翅膀,這裡假設為翅膀)

這時,需要改程式碼了:

如果這樣改:

public class Animal {
	
	 void move(String animal){
		if("鳥".equals(animal)){
			System.out.println(animal + "是主要靠翅膀來移動的");
		}
		else{
			System.out.println(animal + "是主要用腳來移動的");
		}
	}
}
沒錯,可以真確輸出,但違背了單一職責原則,假如又要分為類似於貓頭鷹等主要靠翅膀在夜間移動的鳥,和靠翅膀在白天移動的鳥,又該如何呢,,,再分呢?

這個時候就要考慮單一職責原則了:

第一種:好像有點違背,但在方法上又好像不違背:

public class Animal {
	
	 void move(String animal){
			System.out.println(animal + "是主要靠翅膀來移動的");
		}
    void moveN(String animal){
			System.out.println(animal + "是主要用翅膀來移動的");
		}
    
}
第二種:

用兩個類,即一個類管理一個原則:

public class Animal {
	
	 void move(String animal){
			System.out.println(animal + "是主要靠翅膀來移動的");
		}

}

public class Birds {
	void move(String animal) {
		System.out.println(animal + "是主要靠翅膀來移動的");
	}
}
測試類:
public class SRPTest {

	public static void main(String[] args) {
		Animal animal = new Animal();
		animal.move("狗");
		animal.move("貓");
		animal.move("老鼠");
		Birds birds = new Birds();
		birds.move("鳥");

	}

}


二,開放封閉原則:對擴充套件---開發 , 對更改----封閉

英文:OpenClosePrinciple

簡寫:OCP

就是說:不要更改原始碼(現有程式碼),而應該增加一個新的類(如子類等)

如版本更新等

版本更新:儘量不更改原始碼,可以增加新功能

員工遲到問題:可以制定遲到的晚下班,遲到多久就得加班多久等制度

即:上班總時長封閉,對於遲到一點開放

三,里氏代換原則:子代父,程式行為不變化(有點類似於繼承)

英文:Liskov Substitution Principle 

簡寫:LSP

理解:子類必須能夠替換他們的父型別,使得父類模組在不改變的情況下,自己可以用擴充套件性

如  動物,

子:狗,貓,牛

又如一個四則運算的例子:

求加法:

package testtwo;

public class Console {
	int addNumber(int a , int b){
		return (a + b);
	}
}

測試類:
package testtwo;

public class Test {

	public static void main(String[] args) {
		Console console = new Console();
		int result = console.addNumber(8, 2);
		System.out.println("結果是: " + result);
	}
}

輸出結果:

結果是: 10

假如要先求加法再乘法呢,如 (8 + 2)* 4

那麼你可能說我直接在Console更改就行啦,但萬一,你有好多個類使用了Console的例子呢,那麼容易出錯,

於是可以新建類來繼承,Console不變,

如程式碼:

package testtwo;

public class AConsonle extends Console{
	int addNumber(int a , int b){
		return (a + b);
	}
	int mulNumber(int a , int b){
		return (a * b);
	}
}

測試類:
package testtwo;

public class Test {

	public static void main(String[] args) {

		AConsonle aConsole = new AConsonle();
		int c = aConsole.addNumber(8, 2);
		int result = aConsole.mulNumber(c, 4);
		System.out.println("輸出結果是:" + result);
		
	}
}

輸出:

輸出結果是:40

四:依賴倒轉(置)原則:  

英文:Dependence Inversion Principle,

簡稱 DIP

理解:

(1)抽象不應該依賴細節,細節應該依賴於抽象

    (針對介面程式設計,不要針對現實程式設計)

(2)高層模組不應該依賴底層模組,兩個都應該依賴抽象

抽象:指介面或者抽象類


例子1:假如高層要訪問資料庫,這時,習慣性的我們喜歡寫一個類來實現訪問資料庫的操作(低層),

即   高層-------底層--------》資料庫

但這時,突然客戶要求可以根據自己愛好選擇不同的儲存方式呢,又該如何呢?

例子2:通過程式碼例子,

package threetest;

public class Dog  {
	public void eat(){
		System.out.println("狗正在吃飯!");
	}

}

動物類:
public class Animal {
	public void animal (Dog dog){
		dog.eat();
	}
}
測試類:
<pre name="code" class="java">package threetest;

public class Test {
	public static void main(String[] args){
		Animal a = new Animal();
		Dog dog = new Dog();
		a.animal(dog);
		a.animal(dog);
		a.animal(dog);
	
	}
}

輸出結果:

狗正在吃飯!狗正在吃飯!狗正在吃飯!

那麼這個時候,突然想在測試類,再增加貓正在吃飯,該如何改呢?(增加老鼠呢、、、?)

那麼就該想到,依賴抽象,這裡以介面為例:

程式碼:

介面類Ieat:

package threetest;

public interface Ieat {
	public void eat();
}

狗類:

package threetest;

public class Dog  implements Ieat{
	public void eat(){
		System.out.println("狗正在吃飯!");
	}

}

貓類:
package threetest;

public class Cat implements Ieat{
	public void eat(){
		System.out.println("貓正在吃飯!");
	}
}

高層類:
package threetest;

public class Animal {
	public void animal(Ieat ieat){
		ieat.eat();
	}
}

測試類:
package threetest;

public class Test {
	public static void main(String[] args){
		Animal a = new Animal();
		Dog dog = new Dog();
		Cat cat = new Cat();
		a.animal(dog);
		a.animal(dog);
		a.animal(dog);
		a.animal(cat);
		a.animal(cat);
		a.animal(cat);
	}
}

輸出結果:
狗正在吃飯!
狗正在吃飯!
狗正在吃飯!
貓正在吃飯!
貓正在吃飯!
貓正在吃飯!

由此可見:高層類Animal依賴於抽象(這裡是介面)

              底層類 :Cat , Dog 也依賴於抽象(這裡是介面)

五,迪米特法則:降低類之間的耦合

英文(Law of Demeter,LoD)也稱為最少知識原則(Least Knowledge Principle,LKP)

根本思想:是強調了類之間的鬆耦合,

.....類對自己依賴的類知道的越少越好

 ......與直接朋友交流

直接朋友包括:

1)當前物件本身(this)
2)以參量形式傳入到當前物件方法中的物件
3)當前物件的例項變數直接引用的物件
4)當前物件的例項變數如果是一個聚集,那麼聚集中的元素也都是朋友
5)當前物件所建立的物件
任何一個物件,如果滿足上面的條件之一,就是當前物件的"朋友";否則就是"陌生人"。

也可以說:

出現在成員變數、方法的輸入輸出引數中的類稱為成員朋友類,而出現在方法體內部的類不屬於朋友類。

例子:

Animal類:Dog類屬於直接朋友類,因為它是通過方法的輸入輸出引數成為朋友的,當Foot在方法體count內,不屬於直接朋友

方法屬於類的行為,一個類竟然不知道他的行為與其他類有依賴關係,這就違反了迪米特法則。

package fourtest;

import java.util.ArrayList;
import java.util.List;

public class Animal {
	public void count(Dog dog) {
		List<Foot> list = new ArrayList<Foot>();
		for(int i = 0 ; i < 10 ; i++){
			list.add(new Foot());
		}
		dog.countFoot(list);
		
	}
}
</pre><pre name="code" class="java">Dog類:
</pre><pre name="code" class="java"><pre name="code" class="java">package fourtest;
import java.util.List;
public class Dog {
	void countFoot(List list){
		System.out.println("腳共有 :" + list.size() + "只");
	}
}
Foot類:這裡不寫程式碼
package fourtest;
public class Foot {

}

測試類:
package fourtest;
public class Test {
	public static void main(String[] args){
		Animal al = new Animal();
		Dog dog = new Dog();
		al.count(dog);
	}
}

輸出:
腳共有 :10只
沒錯,結果沒錯,但卻違背了迪米特法則。

應該改為:

Animal類:

package fourtest;
import java.util.ArrayList;
import java.util.List;
public class Animal {
	public void count(Dog dog) {
		dog.countFoot();
		
	}
}
Dog類:
package fourtest;
import java.util.ArrayList;
import java.util.List;
public class Dog {
	public List<Foot> list ;
	public Dog(List<Foot> footList){
		this.list = footList;
	}
	void countFoot(){
		System.out.println("腳共有 :" + list.size() + "只");
	}	
}
Foot類不變,還是沒程式碼:

Test類:

package fourtest;
import java.util.ArrayList;
import java.util.List;

public class Test {
	public static void main(String[] args){
		List<Foot> list = new ArrayList<Foot>();	//建立一個List表,型別為Foot
		for(int i = 0 ; i < 10 ; i++){				//存放資料
			list.add(new Foot());
		}
		Dog dog = new Dog(list);				//建立Dog物件,list作為引數
		Animal al = new Animal();			//建立Animal物件
		al.count(dog);						//呼叫Animal物件的count方法,dog作為物件
		
	}
}
輸出:
腳共有 :10只

又如圖片:


發現每個控制元件都與其他控制元件有關係,這樣如若修改一個控制元件,則可能會帶動其他控制元件,

如若用迪米特法則則可以改為:增加一箇中介(中間類)來管理,如下:




六,介面隔離原則:

英文:Interface Segregation Principle

簡寫:ISP

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

注意:
   (1)介面儘量小,但是要有限度。

   (2)為依賴介面的類定製服務,只暴露給呼叫的類它需要的方法,它不需要的方法則隱藏起來。
   (3)提高內聚,減少對外互動。使介面用最少的方法去完成最多的事情。

舉個例子:

Animal介面:

package fivetest;
interface Animal {
	public void eat();
	public void move();
	public void sleep();
	public void relax();
}
類Dog:
package fivetest;
public class Dog implements Animal{
	//不是abstract,需重寫
	//我們重寫前面三個方法
	public void eat() {
		System.out.println("狗正在吃飯");
	}
	public void move() {
		System.out.println("狗正在移動");
	}
	public void sleep() {
		System.out.println("狗正在睡覺");	
	}
	public void relax() {}
}

Cat類:
package fivetest;
public class Cat implements Animal{
	public void eat() {}
	//這裡重寫後三個方法
	public void move() {
		System.out.println("貓正在移動");	
	}
	public void sleep() {
		System.out.println("貓正在睡覺");		
	}
	public void relax() {
		System.out.println("貓正在休息");	
	}
}

Danimal類:
package fivetest;

public class Danimal {
	public void a1(Animal animal){
	    animal.eat();
	}
	public void a2(Animal animal){
		animal.move();
	}
	public void a3(Animal animal){
		animal.sleep();
	}
}

Canimal類:
package fivetest;

 class Canimal {
	public void b2(Animal animal){
		animal.move();
	}
	public void b3(Animal animal){
		animal.sleep();
	}
	public void b4(Animal animal){
	    animal.relax();
	}
}
測試類:Test
package fivetest;

public class Test {
	public static void main(String[] args){

		Canimal c = new Canimal();
		Cat cat   = new Cat();
		c.b2(cat);
		c.b3(cat);
		c.b4(cat);
		
		Danimal d = new Danimal();
		Dog   dog = new Dog();
		d.a1(dog);
		d.a2(dog);
		d.a3(dog);
	}	
}
輸出結果:
貓正在移動
貓正在睡覺
貓正在休息
狗正在吃飯
狗正在移動
狗正在睡覺
利用迪米特法則改後代碼為:

介面:4個:

public interface Eat {
	public void eat();
}

public interface Move {
	public void move();
}

public interface Sleep {
	public void sleep();
}

public interface Relax {
	public void relax();
}

Dog類:
public class Dog implements Eat , Move , Sleep{
	//我們重寫前面三個方法
	public void eat() {
		System.out.println("狗正在吃飯");
	}
	public void move() {
		System.out.println("狗正在移動");
	}
	public void sleep() {
		System.out.println("狗正在睡覺");	
	}
}

Cat類:
public class Cat implements Move , Sleep , Relax{
	//這裡重寫後三個方法
	public void move() {
		System.out.println("貓正在移動");	
	}
	public void sleep() {
		System.out.println("貓正在睡覺");		
	}
	public void relax() {
		System.out.println("貓正在休息");	
	}
}
Danimal類:
public class Danimal {
	public void a1(Eat e){
	    e.eat();
	}
	public void a2(Move m){
		m.move();
	}
	public void a3(Sleep s){
		s.sleep();
	}
}

Canimal類:
 class Canimal {
	public void b2(Move m){
		m.move();
	}
	public void b3(Sleep s){
		s.sleep();
	}
	public void b4(Relax r){
	    r.relax();
	}
}

測試類:
public class Test {
	public static void main(String[] args){

		Canimal c = new Canimal();
		Cat cat   = new Cat();
		c.b2(cat);
		c.b3(cat);
		c.b4(cat);
		
		Danimal d = new Danimal();
		Dog   dog = new Dog();
		d.a1(dog);
		d.a2(dog);
		d.a3(dog);
	}	
}

輸出結果:
貓正在移動
貓正在睡覺
貓正在休息
狗正在吃飯
狗正在移動
狗正在睡覺




相關推薦

設計模式六大原則

一,單一職責原則:就一個類而言,應該僅有一個引起它變化的原因(就是實現類要責任單一) 英文--Single Responsibility Principle  簡寫:SRP 舉個例子:    父類:Animal public class Animal { vo

設計模式六大原則之裏氏替換原則

number -h ole 擁有 method about rect sse 程序 1 裏氏替換原則定義 Liskov於1987年提出了一個關於繼承的原則“Inheritance should ensure that any property proved about su

設計模式--六大原則

活性 tro 開閉 拆分 其中 com att 隔離 裏氏替換原則 設計模式六大原則 單一職責原則: 不要存在多於一個導致類變更的原因。**通俗的說,即一個類只負責一項職責 裏氏替換原則: 裏氏替換原則通俗的來講就是:子類可以擴展父類的功能,但不能改變父

設計模式六大原則(6):開閉原則

思考 外部 編程人員 恰恰 單一職責 何事 適應 擴展 分享 開閉原則 定義:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。 問題由來:在軟件的生命周期內,因為變化、升級和維護等原因需要對軟件原有代碼進行修改時,可能會給舊代碼中引入錯誤,也可能會使我們不得不對

【大話設計模式】——設計模式基礎

表示 無用功 隱式 art -s -m 個人 pri one   初學設計模式給我最大的感受是:人類真是偉大啊!單單是設計模式的基礎課程就讓我感受到了強烈的生活氣息。個人感覺《大話設計模式》這本書寫的真好。讓貌似非常晦澀難懂的設計模式變的生活化。趣味化。   以下淺談一

設計模式六大原則

編程 color 什麽 例子 進行 函數 細節 增加 客戶 1、開閉原則:Open Close Principle 是軟件實體(類,模塊,函數等)應該可以擴展,但是不可修改。 理解:只以基於原本的來擴展功能,但不能修改原本的代碼。已經面對需求時,對程序的改動是通過增加新

11設計模式六大原則——開閉原則

職責 art 並不是 錯誤 接口 屬於 倒置 編程 探討 定義:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。 問題由來:在軟件的生命周期內,因為變化、升級和維護等原因需要對軟件原有代碼進行修改時,可能會給舊代碼中引入錯誤,也可能會使我們不得不對整個功能進行重構,

java設計模式六大原則

設計者 做的 設計模式 員工 打印 temp 有一種 基於 imp 目錄: 設計模式六大原則(1):單一職責原則 設計模式六大原則(2):裏氏替換原則 設計模式六大原則(3):依賴倒置原則 設計模式六大原則(4):接口隔離原則 設計模式六大原則(5):迪米特法則 設計模式六

設計模式六大原則(2):裏氏替換原則

tr1 裏氏替換原則 style tar 裏氏替換 href target 替換 設計模式 XN潮寺贛3PF鋁73瓷Hhttp://weibo.com/p/1005056364252732 壇2偈6v實8uka誆敲wmhttp://weibo.com/p/10050563

設計模式六大原則(轉)

method 過多 這樣的 不同 提高 依賴倒置 同心圓 23種設計模式 變化 設計模式六大原則(1):單一職責原則 定義:不要存在多於一個導致類變更的原因。通俗的說,即一個類只負責一項職責。 問題由來:類T負責兩個不同的職責:職責P1,職責P2。當由於職責P1需求發

設計模式六大原則(一):單一職責原則

控制 line 避免 多人 由來 pan 兩個類 思想 功能 單一職責定義: 不要存在多於一個導致類變更的原因,通俗的說,即一個類只負責一項職責。 問題由來: 類T負責兩個不同的職責:職責P1,職責P2。當由於職責P1需求發生改變而需要修改類T時,有可能會導致原

設計模式六大原則(4):接口隔離原則

說明 兩個 復雜 試圖 所有 類圖 系統 客戶端 face 定義:客戶端不應該依賴它不需要的接口;一個類對另一個類的依賴應該建立在最小的接口上。 問題由來:類A通過接口I依賴類B,類C通過接口I依賴類D,如果接口I對於類A和類B來說不是最小接口,則類B和類D必須去實現他

[轉]設計模式六大原則[5]:迪米特法則

順序分配 intall 其他 過程 封裝 this 模塊 修改 最好 定義:一個對象應該對其他對象保持最少的了解。 問題由來:類與類之間的關系越密切,耦合度越大,當一個類發生改變時,對另一個類的影響也越大。 解決方案:盡量降低類與類之間的耦合。   自從我們接觸編程開

[轉]設計模式六大原則[6]:開閉原則

說了 一點 模塊 活性 問題 單一職責原則 就是 認識 適應 定義:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。 問題由來:在軟件的生命周期內,因為變化、升級和維護等原因需要對軟件原有代碼進行修改時,可能會給舊代碼中引入錯誤,也可能會使我們不得不對整個功能進行

[轉]設計模式六大原則[4]:接口隔離原則

職責 活性 六大原則 方案 朋友 oid 專用 出現 即使 定義:客戶端不應該依賴它不需要的接口;一個類對另一個類的依賴應該建立在最小的接口上。 問題由來:類A通過接口I依賴類B,類C通過接口I依賴類D,如果接口I對於類A和類B來說不是最小接口,則類B和類D必須去實現他們

Java設計模式六大原則或者說七大原則

設計 sub 隔離 single lose 開閉原則 bili div 依賴倒轉原則 1.開閉原則(Open Close Principle) 2.裏氏代換原則(Liskov Substitution Principle) 3.依賴倒轉原則(Dependence Inver

(讓BAT的Offer不再難拿)設計模式在iOS開發實戰項目中的應用

設計模式的 簡化 情況 結合 在線 百度 是個 開發 方案 在我們日常的開發中設計模式伴隨著項目的各個模塊,巧妙地使用設計模式可以讓我們寫出更高效,簡潔,優美的代碼。可是因為對於設計模式的不熟悉,很多高效的設計模式並沒有被很好地使用起來,現在包括曾經寫的一些代碼,然後在優化

設計模式-六大原則

改變 開閉 目的 但是 了解 關閉 軟件 設計 模塊 一,單一職責原則 不要存在多於一個導致類變更的原因。 二,裏氏代換原則 子類可以擴展父類的功能,但是不能改變父類原有的功能。 三,依賴倒置原則 高層模塊不應該依賴底層模塊,二者都應該依賴其抽象了;抽象不依賴細節;細節應該

面試寶典-設計模式六大原則

面試 軟件 負責 面向 可維護性 迪米特法則 接口隔離原則 定義 輸入 1、單一職責原則 定義:不要存在多於一個導致類變更的原因。通俗的說,即一個類只負責一項職責。 遵循單一職責原的優點有: 可以降低類的復雜度,一個類只負責一項職責,其邏輯肯定要比負責多項職責簡單的多

JAVA23種設計模式六大原則,資料結構演算法強化訓練

目錄: 設計模式六大原則(1):單一職責原則 設計模式六大原則(2):里氏替換原則 設計模式六大原則(3):依賴倒置原則 設計模式六大原則(4):介面隔離原則 設計模式六大原則(5):迪米特法則 設計模式六大原則(6):開閉原則 設計模式六大原則(1):單一職責原則 定義:不要存在多於一個導致