1. 程式人生 > >工廠模式(自己的理解和實現)

工廠模式(自己的理解和實現)

最近學習了工廠模式,看了網上的教程,也學習了別人的程式碼,最後自己按照自己的想法實現了一下。

如果想要看我自己實現的原始碼的,去這個網址下載。支援下小弟工作和學習熱情,辛苦整理實現的,收取1分哈~~~大家別拍磚~~~大笑。順帶說一下怎麼能快速的獲取積分來下載,你可以經常上傳你自己覺得很經典的書籍、文件、程式碼,乃至你自己寫的一些小Demo,並設定一定的積分(別太高了,否則沒人會怎麼下,1-2分最好了),只要你的東西夠好,就會有人下載學習的。人人奉獻嘛~~~

好吧,有點扯遠了。下面來看我自己理解的工廠模式。

溫馨提示:請大家仔細分析和理解下文中前兩種模式實現後的分析段落,原文作者真的寫的很好。在這裡表示敬意。

一、引子

話說在C語言這種面向過程的語言中,如果實現一個人去開車,是需要按照過程來一步一步的完成的,例如想開賓士了,就會說“開賓士車”,想開寶馬了,就說“開寶馬車”,想開奧迪了,就說“開奧迪車”。有沒有覺得很麻煩?想到開什麼車了,就必須要把車名也都帶上,或者需要自己去生成一個車的物件來開。那麼可不可以在Java語言中,充分的體現面向物件的特徵呢?當然可以了,就是增加一個輔助的人來幫你,比如是一個司機。由他來具體負責今天開什麼車,處理內部的邏輯,而你呢?只需要簡簡單單的說一句,“D~~r~~~ive!”。

喏,工廠模式出現了~~~你就好比一個客戶端,司機就好比一個工廠,業務邏輯有它來處理。

二、工廠模式的分類

工廠模式按照範圍或者抽象程度來說,可以大致分為三類:

1、簡單工廠模式(Simple Factory)。這是最簡單、最具體的一種,也是大多小型程式完全可以應付的一種。

2、工廠方法模式(Factory Method)。把簡單工廠模式更加抽象化了,適合更加複雜、OO要求更高的程式或設計。

3、抽象工廠模式(Abstract Factory)。最抽象,但最具一般性的一種。

三、使用工廠模式的情景和前提

那麼工廠模式這麼好,我們需要在什麼情況下使用呢?大致有兩種:

1.在編碼時不能預見需要建立哪種類的例項。
2.系統不應依賴於產品類例項(例如本文的車)如何被建立、組合和表達的細節。

**********************************************我是華麗的分割線*************************************************************************************************

好,下面開始正式的,講三種工廠模式的前兩種。

四、簡單工廠模式

簡單工廠模式,顧名思義就是模式比較簡單,實現起來比較具體的。

組成的三種角色分別為:

1、工廠類角色  :這是本模式的核心,含有一定的商業邏輯和判斷邏輯。在java中它往往由一個具體類實現。例如你僱的司機,由他來處理你想開車的邏輯。
2、抽象產品角色:它一般是具體產品繼承的父類或者實現的介面。在java中由介面或者抽象類來實現。例如車這個模型,它是所有你想開的車的父類或介面。
3、具體產品角色:工廠類所建立的物件就是此角色的例項。在java中由一個具體類實現。例如具體的某輛車,賓士?寶馬?奧迪?

具體的類圖請看下面:


好,來簡單實現以下吧

來定義一個抽象產品角色:Car

/**
 * 作為抽象產品類,即它只代表是某種產品,具體的細節由具體的產品來實現。
 *
 */
public interface Car {
	
	/**
	 * 子類需要實現的方法,具體如何開動
	 */
	public abstract void drive();

}
Car類代表抽象的產品,是所有具體產品的父類。提供的開車方法,由具體的產品去實現。

再來定義具體產品角色:Benz、BMW、Audi

/**
 * 賓士車,繼承與Car,實現了具體的開車細節
 */
public class Benz implements Car{

	@Override
	public void drive() {
		// TODO Auto-generated method stub
		System.out.println("賓士車啟動,嗡~~~~");
	}

}

/**
 * 寶馬車,繼承與Car,實現了具體的開車細節
 */
public class BMW implements Car{

	@Override
	public void drive() {
		// TODO Auto-generated method stub
		System.out.println("寶馬車啟動,嗡~~~~");
	}

}

/**
 * 奧迪車,繼承於Car,實現了具體的開車細節。
 */
public class Audi implements Car{

	@Override
	public void drive() {
		// TODO Auto-generated method stub
		System.out.println("奧迪車啟動,嗡~~~~");
	}

}


這三個就是具體產品角色,是真正存在的車 。

下面,來最重要的工廠角色了,Driver。

/**
 * 工廠類,由它來具體實現一些邏輯和業務上的細節
 *
 */
public class Driver {
	
	
	/**
	 * 啟動一輛車,通過具體傳入的車名,來生成並返回該車。
	 * 
	 * @param carName 需要開的車名。Benz,BMW,Audi
	 * @return car 具體生成的車。注意多型。
	 * @throws Exception 沒有找到傳入的車名時報出異常。
	 */
	public static Car launch(String carName) throws Exception{
		
		if( "Benz".equals(carName)){
			return new Benz();
		}else if("BMW".equals(carName)){
			return new BMW();
		}else if("Audi".equals(carName)){
			return new Audi();
		}else{
			throw new Exception("沒有該車型:" + carName );
		}
	}

}

Driver類就是工廠類,它負責具體的業務邏輯。例如你想開什麼車,就傳入車名,由他來處理這個名字,併為你提供這輛車。如果沒有,則會告訴你一些錯誤。

該類有一個方法launch(),就是有它來處理業務細節的。具體怎麼實現,還要看具體的需求,這裡只是舉例。

最後,該我們上場了,Supremo!!

public class Supremo {
	public static void main(String[] args){
		
		try {
			Car car = Driver.launch("Benz");
			car.drive();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}


看到了嗎?我們只是告訴司機我們想要開的車,司機就會自己進行處理並返回給我們,然後我們呼叫drive方法,就有具體的某輛車去執行開車方法了。

這便是簡單工廠模式了。怎麼樣,很簡單吧?那麼它帶來了什麼好處呢?
首先,使用了簡單工廠模式後,我們的程式不在“有病”,更加符合現實中的情況;
其次,客戶端免除了直接建立產品物件的責任,而僅僅負責“消費”產品(正如我們的行為)。


下面我們從開閉原則上來分析下簡單工廠模式。
當我們增加了一輛車的時候,只要符合抽象產品制定的原則,那麼只要通知工廠類知道就可以被客戶使用了。
那麼對於產品部分來說,它是符合開閉原則的——對擴充套件開放、對修改關閉;
缺點:
但是工廠部分好像不太理想,因為每增加一輛車,都要在工廠類中增加相應的商業邏輯和判斷邏輯,這顯自然是違背開閉原則的。
對於這樣的工廠類(在我們的例子中是為司機師傅),我們稱它為全能類或者上帝類。我們舉的例子是最簡單的情況,而在實際應用中,很可能產品是一個多層次的樹狀結構。由於簡單工廠模式中只有一個工廠類來對應這些產品,所以這可能會把我們的上帝類壞了,進而累壞了我們可愛的程式設計師:(


正如我前面提到的簡單工廠模式適用於業務將簡單的情況下。而對於複雜的業務環境可能不太適應阿。這就應該由工廠方法模式來出場了!!

五、工廠方法模式

上一種方法雖然很體現工廠設計模式,但過於簡單,所有的邏輯都在一個類裡實現,或多或少有點坑人的感覺啊,豈不是要累死人?萬惡的資本主義了???

我們人類太聰明瞭,發現問題了怎麼辦?馬上改進現有的機制唄。

在這種情況之下衍生了工廠方法模式,產品們還是依舊的產品們,但工廠?可不是曾經的那個工廠啦。“產房傳喜訊,人家生(升)啦”。

怎麼個意思?記得曾經的那個Driver類麼?現在,它已經變成了一個司機部門的主管,由具體的實現類,變成了一個父類(介面)。但只有一個光桿司令是不行滴,所以要招聘員工了,王師傅(賓士司機)、李師傅(寶馬司機)、張師傅(賓士司機)都來應聘成功!!!

來看看工廠方法模式的組成角色,比簡單工廠多了一個角色

1、抽象工廠類角色:工廠的抽象,是一般工廠的父類或實現的介面。在Java中由一個介面或抽象類來實現。例如我們程式的司機部門主管。
2、工廠類角色    :這是本模式的核心,含有一定的商業邏輯和判斷邏輯。在java中它往往由一個具體類實現。例如你僱的司機,由他來處理你想開車的邏輯。
3、抽象產品角色  :它一般是具體產品繼承的父類或者實現的介面。在java中由介面或者抽象類來實現。例如車這個模型,它是所有你想開的車的父類或介面。
4、具體產品角色  :工廠類所建立的物件就是此角色的例項。在java中由一個具體類實現。例如具體的某輛車,賓士?寶馬?奧迪?

具體的類圖如下:

來看看實現吧~~~在簡單工廠的基礎之上,所有的產品都是不用動滴~~~需要改變的只是工廠類部門。

改動後的Driver

/**
 * 工廠的介面,由它來定義一些需要完成的業務和邏輯,由具體的工廠去實現。例如司機部門主管。
 *
 */
public interface Driver {
	public abstract Car launchCar();
}
怎麼樣?人家現在不管怎麼處理車了,人家只管發號施令,具體什麼車,你們不是有自己專門的司機麼?

來看看司機們吧~~~王師傅、李師傅、張師傅登場~~~

/**
 * 賓士司機,繼承於Driver,是一個具體的工廠類。
 */
public class BenzDriver implements Driver{

	@Override
	public Car launchCar() {
		// TODO Auto-generated method stub
		
		return new Benz();
	}

}

/**
 * 寶馬司機,繼承於Driver,是一個具體的工廠類。
 */
public class BMWDriver implements Driver{

	@Override
	public Car launchCar() {
		// TODO Auto-generated method stub
		return new BMW();
	}

}

/**
 * 奧迪司機,繼承於Driver,是一個具體的工廠類。
 */
public class AudiDriver implements Driver{

	@Override
	public Car launchCar() {
		// TODO Auto-generated method stub
		return new Audi();
	}

}

三個司機都歸Driver類管,具體開什麼車,他們自己會去負責。

當然我們的行為也是需要改的,我們只要去告訴主管去開哪個車就好了

public class Supremo {
	public static void main(String[] args){
		
		// 告訴主管我們需要一個賓士車。
		Driver driver = new BenzDriver();
		Car car = driver.launchCar();
		car.drive();
		
	}

}

我們今天心情高興,告訴主管我們想要開大奔粗們~~~主管就會很聽話的告訴賓士的師傅來準備好賓士車了。

工廠方法使用一個抽象工廠角色作為核心來代替在簡單工廠模式中使用具體類作為核心。
讓我們來看看工廠方法模式給我們帶來了什麼?使用開閉原則來分析下工廠方法模式。
當有新的產品(即我們的汽車)產生時,只要按照抽象產品角色、抽象工廠角色提供的原則來生成,那麼就可以被客戶使用,而不必去修改任何已有的程式碼。看來,工廠方法模式是完全符合開閉原則的!
使用工廠方法模式足以應付我們可能遇到的大部分業務需求。但是當產品種類非常多時,就會出現大量的與之對應的工廠類,這不應該是我們所希望的。所以我建議在這種情況下使用簡單工廠模式與工廠方法模式相結合的方式來減少工廠類:即對於產品樹上類似的種類(一般是樹的葉子中互為兄弟的)使用簡單工廠模式來實現。

抽象工廠模式我還木有看懂,希望大家先看上面的,後面的我再理解理解,有需要的可以看本文開頭的部分,有原帖地址。