1. 程式人生 > >OOAD之設計模式

OOAD之設計模式

一、模式:

避免重複問題,而提出來的解決方案。

模式又可以分為:

架構模式  

設計模式

 

1.1架構模式

軟體架構的上,整體考慮,而提出來的一些解決方案,比如:三層架構,B/S,C/S,MVC,ORM,事務指令碼,領域模型……,從巨集觀的角度上來說

 

1.2設計模式

設計模式是從微觀的角度上來看待軟體開發過程中,碰到的一些重複業務場景,並提出的解決方案。

 

設計模式:建立性設計模式,結構性設計模式,行為性設計模式

**建立性設計模式:**更多的關注物件如何建立,而提出來的各種建立方案

**結構性設計模式:**更多的關注於類和類,物件和物件的整體結構,而提出來的各種解決方案

**行為性設計模式:**更多的關注於例項之間的行為互調,以及職責分配的問題

 

1.2.1分類

*建立性設計模式中:**

簡單工廠模式

靜態工廠方法(Static Factory Method)

抽象工廠(Abstract Factory)

單例模式(Singleton)

原型模式(Prototype)

建造模式(Builder)

 

**結構性設計模式中:**

介面卡模式(Adapter)

橋接模式(Bridge)

複合模式(Composite)

裝飾器模式(Decorator)

外觀模式(Façade)

享元模式(FlyWeight)

代理模式(Proxy)

 

**行為性設計模式:**

直譯器模式(Interpreter)

模板方法模式(Template Method)

職責鏈模式(Chain of Responsibility)

命令模式(Command)

迭代器模式(Iterator)

中介者模式(Mediator)

備忘錄模式(Memento)

觀察者模式(Observer)

策略模式(Strategy)

狀態模式(State)

訪問者模式(Visitor)

 

1.2.1詳細介紹

**1、簡單工廠模式**

簡單工廠模式,又被稱之為“靜態工廠方法”模式,該模式會專門定義一個“工廠類”,然後在工廠類提供一個靜態方法,有該靜態方法根據使用者的輸入,動態決定建立什麼型別的物件。通常來說:工廠類的產生的物件,都有一個特點,具備相同的父類,或者具備相同的介面

簡單工廠的3種角色:工廠類,產品的抽象類(介面),具體的產品

1)工廠類:主要負責根據使用者的輸入,動態的產生具體的產品

2)產品抽象類|介面:對具體產品進行類的抽象或者行為的抽象

3)具體的產品:工廠類產生的具體例項

簡單工廠模式的作用:

將客戶呼叫類上的2個職責(建立物件的職責,呼叫物件的行為的職責),進行職責分離,讓呼叫類最終只存在1個職責(呼叫物件的行為的職責),而將建立物件的職責,委託給工廠類。

簡單工廠模式的缺點:

簡單工廠,實際上將物件的產生,由之前的客戶呼叫類身上,強制性的定義在工廠類身上,工廠類此時具備一定的建立物件的業務邏輯,以及一些判斷邏輯。那麼如果具體的產品,需要發生變化,或者有新的產品需要擴充套件,那麼毫無疑問,此時就需要去針對工廠類做相應的變化,那麼無形當中就違背了“開閉原則”,“單一原則”,“依賴倒轉原則”

注意:

簡單工廠模式,只能產生同一家族(繼承相同類,實現相同介面)的產品,非同一家族的產品,簡單工廠是無法使用的。

 

**2、抽象工廠方法模式:**

簡單工廠模式,會出現一些問題,比如:呼叫類和工廠類直接耦合(依賴倒轉原則),工廠類中無法滿足“開閉原則”,因為工廠類中方法存在一定的業務邏輯和判斷邏輯,如果需要新增新的產品,工廠類也需要去做相應的修改,所以違背了“開閉原則”

為了規避上述問題,所以才有了抽象工廠方法模式,該模式實際上就是在工廠類的基礎上,進一步進行工廠抽象,然後每一個獨立的產品,都對應一個具體的產品工廠,通過這種方式來實現程式滿足“開閉原則”

在呼叫類中使用面向介面程式設計,來解決上述的呼叫類和工廠類直接耦合的問題。

抽象工廠模式有4種角色:

1、工廠的抽象類  完成對產品生產工廠進行抽象

2、具體產品的生產工廠   分別對產品進行生產

3、產品抽象類|介面:對具體產品進行類的抽象或者行為的抽象

4、具體的產品:工廠類產生的具體例項

 

**3、原型模式(克隆模式):**

原型模式:如果某一個類存在大量的屬性,然後又需要大量產生該類的相同或者相似的物件的時候,我們就可以使用克隆模式。克隆就是指以什麼東西作為參照,大量產生新的物件。

如果大量的物件在產生的時候,大部分的屬性或者絕大多數的屬性都一樣,而只有少量的屬性存在差異時,此時,我們就可以使用原型模式。

JAVA中原型模式,實現方式非常簡單:實現Cloneable介面,並重寫clone()就可以完成物件的“淺克隆”,如果物件的關聯物件也需要克隆的話,那麼就需要關聯物件也要實現實現Cloneable介面,並重寫clone(),並且物件克隆時,還要通知關聯物件也去克隆,從而做到“深度克隆”。

例子:

 @Override
	public Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		//加了下面這句話,就叫深度克隆
		this.setWife((Wife)wife.clone());
		return super.clone();
	}

 

**4、單例模式:**

單例模式:如果碰到某種業務場景,如果一個類在整個軟體範圍內,都只需要擁有1個例項的時候,我們就可以使用單例模式。

例如:多臺電腦,對應1臺印表機,那麼印表機在區域網範圍內,就只有1個單例項

 

單例項的實現方式

懶漢式:

  /**
	 * 懶漢,執行緒不安全版 1.0版本
	 * @return
	 */
	public static RandomSingleton getInstance() {
		if (instance == null) {
			instance = new RandomSingleton();
		}
		return instance;
	}
/**
	 * 懶漢,執行緒安全版2.0版本
	 * @return
	 */
	public static RandomSingleton getInstance() {
		synchronized (instance) {
			if (instance == null) {
				instance = new RandomSingleton();
			}
			return instance;
		}
	}
/**
	 * 懶漢,執行緒安全版2.2版本
	 * 雙重檢測機制
	 * @return
	 */
	public static LazyManSingleton getInstance() {
		if (instance == null) {
			//1,2,3,4……所有的執行緒
			synchronized (LazyManSingleton.class) {
				
				if(instance == null) {
					instance = new LazyManSingleton();
				}
				
			}
		}
		return instance;
	}


餓漢式:   

/**
     * 單例模式(餓漢式)
     * @author Administrator
     */
    public class HungryManSingleton {
    
    	private static HungryManSingleton instance = new HungryManSingleton();
    	
    	private HungryManSingleton() {
    		// TODO Auto-generated constructor stub
    	}
    	
    	/**
    	 * 天生就是執行緒安全的
    	 * @return
    	 */
    	public static HungryManSingleton getInstance() {
    		return instance;
    	}
    } 

推薦大家,直接使用餓漢式記住:沒有痴漢式,飽漢式……

 

**5、介面卡模式:**

當兩個類 ,或者說兩個元件需要相互通訊的時候,然後兩個類又無法直接互動的情況下,比如:美國教練無法直接指揮外籍球員“何憨鋒”時,“何憨鋒”聽不懂英文,那麼此時就需要一個介面卡|翻譯員,來幫我們做一箇中間翻譯,或者適配的工作!

 

**6、觀察者模式:**  

比如:大家在上高中的時候,一大幫觀察老師的情況          

比如:商家的貨品在降價時,自動通知所有關注該商品的使用者

 

觀察者模式,定義了一種1對多的依賴關係,讓多個觀察者物件同時監聽|觀察同一個主題,當主題的狀態發生變化的時候,可以讓這些多個觀察者自動重新整理他們自己。當然這個過程,是由主題來通知觀察者發生

如下面這個檔案表結構:

observer檔案下的Observer抽象類(觀察者)、Subject抽象類(被觀察者)、MainEnter是測試用的;

impl子檔案下的Teacher類(被觀察者)繼承了Subject抽象類(被觀察者),PlayGameStudent、ReadNovelStudent、SeePhoneStudent是繼承了Observer抽象類(觀察者);

 

在上面中,老師是被觀察者,同學們是觀察者。

老師類中有個狀態屬性,當被觀察者老師的狀態改變後,需要通過老師類中的告知方法,去告知同學自己的狀態發生了改變,然後同學去執行相應動作。

在老師類中有個集合用於裝下所有不同的同學;

再告知方法中,通過判斷老師目前的狀態,然後在狀態特定的情況下才去執行同學帶有的方法,比如看小說等等,同學們的這些行為都是繼承於他們的抽象類,只是不同的實現。通過foreach迴圈方法就可把集合中的同學得到,然後執行同學類的方法。

 

**7、代理模式**

代理模式給某一個物件提供一個代理物件,並由代理物件控制對原物件的引用。通俗的來講代理模式就是我們生活中常見的中介。

舉個例子來說明:假如說我現在想買一輛二手車,雖然我可以自己去找車源,做質量檢測等一系列的車輛過戶流程,但是這確實太浪費我得時間和精力了。我只是想買一輛車而已為什麼我還要額外做這麼多事呢?於是我就通過中介公司來買車,他們來給我找車源,幫我辦理車輛過戶流程,我只是負責選擇自己喜歡的車,然後付錢就可以了。用圖表示如下:

為什麼要用代理模式?

中介隔離作用:在某些情況下,一個客戶類不想或者不能直接引用一個委託物件,而代理類物件可以在客戶類和委託物件之間起到中介的作用,其特徵是代理類和委託類實現相同的介面。

開閉原則,增加功能:代理類除了是客戶類和委託類的中介之外,我們還可以通過給代理類增加額外的功能來擴充套件委託類的功能,這樣做我們只需要修改代理類而不需要再修改委託類,符合程式碼設計的開閉原則。代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後對返回結果的處理等。代理類本身並不真正實現服務,而是同過呼叫委託類的相關方法,來提供特定的服務。真正的業務功能還是由委託類來實現,但是可以在業務功能執行的前後加入一些公共的服務。例如我們想給專案加入快取、日誌這些功能,我們就可以使用代理類來完成,而沒必要開啟已經封裝好的委託類。

有哪幾種代理模式?

       我們有多種不同的方式來實現代理。如果按照代理建立的時期來進行分類的話, 可以分為兩種:靜態代理、動態代理。靜態代理是由程式設計師建立或特定工具自動生成原始碼,在對其編譯。在程式設計師執行之前,代理類.class檔案就已經被建立了。動態代理是在程式執行時通過反射機制動態建立的。

 

**8、備忘錄模式**

如果某一天,我們存在需要對某一個物件的狀態進行備份的時候,我們就可以去使用“備忘錄模式”,備忘錄模式,要求在不破壞原有物件的封裝的基礎上,讓另外一個物件去記錄原物件的所有狀態,如果某一天,原物件的狀態存在丟失的情況,需要還原時,我們就可以採用另外的物件來進行還原。

備忘錄模式中,存在以下角色:

原物件:它是備份資料的發起者
備忘錄物件:記錄原物件的資料
備忘錄管理者物件:管理備忘錄物件

 

**9、建造者模式**

當生產的產品,具有固定的建造步驟時,就需要大家去使用建造者模式,建造者模式的主要作用:是將物件的生產與物件的行為表現分離,無論你產生的是什麼型別的產品,反正在建造類中都是使用的固定的建造的步驟。建造者模式更多的是用於:封裝某一個具有多個元件組成的產品,比如:電腦,汽車,機器人……

你在生產具有多個元件的產品時,又不想讓其他人知道你詳細的建造過程時,你就可以用建造者模式。

 

**10、裝飾器模式**

當需要給某一個物件,動態新增更多的責任的時候,我們就可以使用裝飾器模式,比如:給小峰峰穿衣服

裝飾的時候,是一層層的裝飾,比如:

//要給小峰峰穿衣服,裝扮
tx.decorate(person);
ld.decorate(tx);
dk.decorate(ld);
htg.decorate(dk);

 

**11、責任鏈模式**

使用場景,稍微要多一些,一般發生在公司具有審批流程時,根據輸入的請求條件,來動態的決定由哪一個上級來處理該請求。如果領導沒有權利處理請求的話,可以直接拋給上級,讓上級接著處理。

責任鏈模式中:一定要確定好上下級關係,以及每一個領導自身所具備的權利大小。

 

**12、抽象工廠模式**

使用場景:現在系統中,存在多套系列的產品,比如:即存在mysql資料庫的產品,又存在SQLServer資料庫的產品,那麼如果做到2套產品之後,可以動態切換,那麼就需要使用到“抽象工廠模式”。