讀秦小波《設計模式之禪》 -- 工廠模式

BruceZhang發表於2014-12-25

      設計模式是一種非常有用的程式設計技巧,它對於程式碼的重構有些非常重要的作用,對於軟體開發人員來說,需要理解並嘗試著使用這些設計的方法。

      個人感覺《設計模式之禪》這本書中講解的非常具體,每個模式都配以適當的例子,非常適合學習設計模式的初學者,當然,程傑的《大話設計模式》也是非常好的一本書,都可以拿過來當做一本工具書隨時檢視理解設計的奧妙。

      

      工廠模式

      這個模式的名字就已經告訴了我們它想要做什麼,就是讓我們構造出一個工廠,然後生產我們需要的東西,即生成物件。那麼,為什麼要構造一個工廠呢,為什麼不直接在程式碼中直接 new 一個出來呢?

      想象這樣一種情況:有時我們設計一類東西時,這一類又包含有許多的具體類,那麼,當我們需要得到這些物件時,如果我們一個一個的 new 出來,就會顯得很粗糙,而且如果構造這些物件時,需要進行一些必要的初始化,而這些初始化操作對於這一類物件都是相似的,那麼,我們的程式碼中就會顯得非常的冗餘,在 new 之後會出現很多相似的初始化物件程式碼。

      這時,你就會想,有這樣一個東西,我只需要告訴它,我需要那個物件,那麼,它就會生成那個物件,而且我不需要考慮到它實際的實現細節。那麼這個東西就叫做工廠。

      工廠模式分為三類:

      簡單工廠模式,工廠模式,抽象工廠模式

      下面就分別對這三個模式進行介紹

      

      簡單工廠模式

      這是最簡單的工廠模式型別,一般的設計會出現三個類或介面:

      1> 抽象產品類或者產品介面

      2> 具體產品類

      3> 工廠類

      注:這裡我想多說幾句關於抽象類和介面的區別,抽象類和介面是非常相似的東西,大部分時候它是可以互相代替的,那麼它們之間存在什麼不同呢?我們從名字中可以看出一個是對一類物件的抽象,一個是類的介面。舉一個例子就好像這樣,人分為黃種人,白種人。。。,那麼,對於人,我們需要設計出一個抽象類還是介面呢?應該設計成為抽象類,因為,它是對人類的抽象,所有的人都應該具有這個特徵。介面呢,什麼應該設計成為介面呢?就好像人的愛好一樣,比如,游泳,檯球,乒乓球(這些都是我的愛好,哈哈),它是後天養成的東西,是需要具體的實現的,所以,這些應該是設計成為介面,所以,一個黃種人的類就好像下面這樣:

      public class YellowHuman extends Human implements Swimming, PingPang ...  { }

      好的,回到前面的簡單工廠裡面,說它簡單,因為這個模式只需要實現一個工廠類就能生產出我們需要的產品,還是以人種的例子(“著名的”女媧造人)做出說明。

      女媧製造出各種人種,黃種人,白種人,黑種人,首先,人具有的共同特點構造出一個抽象類:

public abstract class __Q_Y_Human
{
	abstract void __Q_Y_Color();
	
	abstract void __Q_Y_Talk();
	
	public void __Q_Y_Sex()
	{
		System.out.println("every one has sex : man/woman...");
	}
}
      

      然後,各種人種需要實現這個抽象類,這裡舉例黃種人實現抽象類:

public class __Q_Y_YellowHuman extends __Q_Y_Human{

	@Override
	public void __Q_Y_Color() {
		// TODO Auto-generated method stub
		System.out.println("黃色皮膚。。。");
	}

	@Override
	public void __Q_Y_Talk() {
		// TODO Auto-generated method stub
		System.out.println("一般說的都是雙位元組。。。");
	}

}
      

      工廠類也很容易寫出來,就好像下面這樣:

public class __Q_Y_Factory
{
	/*製造一個黃種人*/
	public __Q_Y_YellowHuman __Q_Y_CreateYellowHuman()
	{
		return new __Q_Y_YellowHuman();
	}
	
	public __Q_Y_BlackHuman __Q_Y_CreateBlackHuman()
	{
		return new __Q_Y_BlackHuman();
	}
	
	public __Q_Y_WhiteHuman __Q_Y_CreateWhiteHuman()
	{
		return new __Q_Y_WhiteHuman();
	}
}
      當我們需要構造出一個人的物件時,只需要呼叫工廠中的方法就可以了,是不是比以前單純的 new 出來要清晰的多了呢!

      不過,這樣會產生出擴充套件問題,假如現在又需要新增一種新的人種 -- 紅種人,怎麼辦呢?具體的人種物件實現起來很簡單,繼承那個抽象類就可以了,那麼,工廠類呢?我們不得不修改工廠中的方法,需要新增加一個,也許你會說這樣也不難呀,新增一個方法就可以了。不過,這僅僅是增加一種人,如果有很多種呢?同時,這也破壞了原來的程式碼結構。所以,一種對簡單工廠模式的改進出現了 -- 工廠模式。
      這個改進了的模式比簡單工廠模式好的地方在於它是建立一個抽象工廠,具體生產產品的工廠需要繼承抽象工廠,實現具體的生產方法以生產需要的不同產品。

      所以,它的思想也是很簡單的,我們首先需要看下抽象工廠的實現:

public abstract class __Q_Y_Factory {
	public abstract <T extends __Q_Y_Human> T __Q_Y_CreateHuman(Class<T> _c);
}
      這裡,它很簡單,只是寫了一個泛型方法,我們限定它的返回型別和引數都是 Human 的子類,下面看看具體實現的工廠類:

public class __Q_Y_HumanFactory extends __Q_Y_Factory {
	@SuppressWarnings("unchecked")
	@Override
	public <T extends __Q_Y_Human> T __Q_Y_CreateHuman(Class<T> _c) {
		// TODO Auto-generated method stub
		__Q_Y_Human _human = null;
		
		try {
			/*這裡就是反射的應用,即僅僅是利用類的名字就能構造它的物件*/
			_human = (__Q_Y_Human)Class.forName(_c.getName()).newInstance();
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("建立人失敗了。。。");
		}
		
		return (T) _human;
	}
}
      可以看到,這個方法根據不同的引數(類名)就可以得到不同的人種了,當我們新增加一個人種的時候,只是需要寫出表示那個人種的類就可以了,其他的都不需要改變。

      為方便看程式碼的結構,下面貼出以上方法的類圖:


      從上面的類圖中可以看到,三類人都繼承自 “人” 的抽象類,具體的工廠也是繼承自工廠抽象類。

      下面介紹抽象工廠模式:

      抽象工廠模式與工廠模式的構造大致是一樣的,它們的區別之處在於抽象兩個字,抽象工廠模式的抽象程度要高於工廠模式,意思是抽象工廠的同一套介面能夠得到不同型別的物件。

      人分為男和女,那麼,程式碼中生產的人也需要分出性別來,如果依照上面的工廠介面我們沒辦法做到這一點,當然,表示人的類也是需要變化的,要有不同膚色的男人類,不同膚色的女人類。首先,我們需要看看人類的設計。

      第一層抽象類:

public abstract class __Q_Y_Human {
	
	public abstract void __Q_Y_Sex();
	
	public abstract void __Q_Y_Color();
}
      第二層抽象類:

public abstract class __Q_Y_YellowHuman extends __Q_Y_Human{

	public void __Q_Y_Color() {
		System.out.println("yellow human...");
	}
}
      第三層具體類(兩個):

public class __Q_Y_MaleYellowHuman extends __Q_Y_YellowHuman{

	@Override
	public void __Q_Y_Sex() {
		// TODO Auto-generated method stub
		System.out.println("male yellow human...");
	}

}
public class __Q_Y_FamaleYellowHuman extends __Q_Y_YellowHuman{

	@Override
	public void __Q_Y_Sex() {
		// TODO Auto-generated method stub
		System.out.println("famale yellow human...");
	}

}
     

      這裡就很明顯了,我們只要構造一個抽象工廠能夠 “生產” 不同類別的人就行了,抽象工廠的定義如下:

public abstract class __Q_Y_Factory {
	
	public abstract __Q_Y_Human __Q_Y_Create();
}

      從上面的例子中可以看到,工廠返回的只是 Human 型別的物件,不知道 Human 的膚色是什麼,也不知道 Human 的性別是什麼。這也就是抽象工廠的意思,它生產出來的物件更為抽象,抽象到可以表示不同的型別的物件。

      好吧,我們看下具體的實現方式是怎麼樣:

      生產黃種男性:

public class __Q_Y_FamaleFactory extends __Q_Y_Factory{

	@Override
	public __Q_Y_Human __Q_Y_Create() {
		// TODO Auto-generated method stub
		return new __Q_Y_FamaleYellowHuman();
	}

}
      生產黃種女性:

public class __Q_Y_MaleFactory extends __Q_Y_Factory{

	@Override
	public __Q_Y_Human __Q_Y_Create() {
		// TODO Auto-generated method stub
		return new __Q_Y_MaleYellowHuman();
	}

}

      當然,除了黃種人,黑種人,白種人都可以自己去實現加到這個模式中,為方便理解模式的構造,貼出抽象工廠模式實現的類圖:



      工廠模式(簡單工廠模式,工廠模式,抽象工廠模式)是實際運用中最多的設計模式,所以,需要理解這種模式,並在實際的軟體開發中嘗試用這種設計模式構造容易理解的架構。


相關文章