設計模式(四)——抽象工廠模式

liangxingwei發表於2017-12-14

本文原創掘金:L_Sivan

不知道看上一篇的時候,有沒有看到一個問題,如果只是簡單的工廠,為什麼要一個抽象工廠類?那個抽象類完全沒必要啊,直接用一個工廠類,傳入class引數,不就行了嗎?這裡就來了,抽象工廠模式。不過說實話,抽象得我快抽風了。。看了幾篇部落格了,最後發現百度百科很強。

抽象工廠模式

  • 定義:為建立一組相關或相互依賴的物件提供一個介面,而且無須指定它們的具體類。
  • 作用:當每個抽象產品都有多於一個的具體子類的時候,工廠角色怎麼知道例項化哪一個子類呢?比如每個抽象產品角色都有兩個具體產品。抽象工廠模式提供兩個具體工廠角色,分別對應於這兩個具體產品角色,每一個具體工廠角色只負責某一個產品角色的例項化。每一個具體工廠類只負責建立抽象產品的某一個具體子類的例項。
  • 是一個建立類模式

上面的定義和作用分別從書上和百度百科看到的,說實話,我並不是很懂,看了好幾篇部落格,結合百度百科,我決定這篇寫成一篇可能會被人罵的文章。

首先還是上程式碼,上看到個人覺得不恰當的例子的程式碼: 大體是模仿工廠製造車吧

// 車介面
public interface CarModel {
	public void alarm();
	public void run();
}
// 實現CarModel介面的抽象車
public abstract class BenzCar implements CarModel{
	@Override
	public void alarm() {
		System.out.println("這是賓士車");
	}
}
// 實現CarModel介面的抽象車
public abstract class BmwCar implements CarModel{
	@Override
	public void alarm() {
		System.out.println("這是寶馬車");
	}
}
// A系列的賓士車
public class ABenzCar extends BenzCar{
	@Override
	public void run() {
		System.out.println("A系列的賓士車在飛馳");
	}
}
// A系列的寶馬車
public class ABmwCar extends BmwCar{
	@Override
	public void run() {
		System.out.println("A系列的寶馬車在飛馳");
	}
}
// 還有B系列的車,是有兩個產品等級的,這裡就不列出來了
// 抽象工廠
public abstract class AbstractCarFactory {
	// 為什麼不能用泛型約束?
	// 因為用了泛型約束,就無法建立這個抽象物件,抽象工廠也就不復存在,為什麼會建立不了這個抽象工廠呢?
	// 因為建立抽象工廠後,子類繼承之後,抽象方法接收的引數並不是某一個具體的產品的class屬性,這意味著,只要是符合這個類約束的子類的class屬性,都可以傳進來,這就沒有不同工廠這種概念了,所以抽象工廠也不存在,因為一個工廠就處理完了。
//	public abstract <T extends BenzCar> T  getBenzCar(Class<T> c);
//	public abstract  <T extends BmwCar> T  getBmwCar(Class<T> c);
	public abstract BenzCar getBenzCar();
	public abstract BmwCar getBmwCar();
}
// 具體工廠
public class ACarFactory extends AbstractCarFactory {
	@Override
	public BenzCar getBenzCar() {
		ABenzCar car = new ABenzCar();
		// doSomething
		return car;
	}
	@Override
	public BmwCar getBmwCar() {
		ABmwCar car = new ABmwCar();
		// doSomething
		return car;
	}
	/*@Override
	public <T extends BenzCar> T getBenzCar(Class<T> c) {
		T car = null;
		try {
			car = (T) Class.forName(c.getName()).newInstance();
			return car;
		} catch (Exception e) {
		}
		return car;
	}*/
}
//場景類
public class Client {
	public static void main(String[] args) {
		ACarFactory aCarFactory = new ACarFactory();
		BenzCar abenzCar =  aCarFactory.getBenzCar();
		abenzCar.alarm();
		abenzCar.run();
		System.out.println("--------------------");
		BmwCar abmwCar = aCarFactory.getBmwCar();
		abmwCar.alarm();
		abmwCar.run();
		System.out.println("--------------------");
		BCarFactory bCarFactory = new BCarFactory();
		BenzCar bbenzCar = bCarFactory.getBenzCar();
		bbenzCar.alarm();
		bbenzCar.run();
		System.out.println("--------------------");
		BmwCar bbmwCar = bCarFactory.getBmwCar();
		bbmwCar.alarm();
		bbmwCar.run();
	}
}
結果:
這是賓士車
A系列的賓士車在飛馳
\--------------------
這是寶馬車
A系列的寶馬車在飛馳
\--------------------
這是賓士車
B系列的賓士車在飛馳
\--------------------
這是寶馬車
B系列的寶馬車在飛馳
複製程式碼

來分析下程式碼,這段程式碼我覺得很有問題的地方,就在於抽象出那個AbstractCarFactory有什麼用,為什麼這麼說?在抽象工廠那裡的註釋,我寫上了,如果只是單純地要劃分產品等級,那我直接實現泛型約束,就像我註釋掉 的程式碼。

//    public abstract <T extends BenzCar> T  getBenzCar(Class<T> c);
//    public abstract  <T extends BmwCar> T  getBmwCar(Class<T> c);
複製程式碼

這樣的話,再建一個SuperFactory,超級工廠,根據傳進來的class屬性,就可以生產出相應的物件。可能有人會說,這個SuperFactory不符合單一職責原則啊,一個類做了多種事,好,那退而求次,選擇兩個類,分別生產A級產品和生產B級產品。然後就會有人說,那就對嘛,而兩個生產的方法還是相同的,為了日後好擴充套件,抽象共同部分出來作為父類,超棒的。但是有沒有想過,就像上面的程式碼,我可以換一種抽象方式,就是BenzCarFactory和BmwCarFactory,然後專門用來生產Benz和Bmw,還可以用泛型約束,方法都省了一個,這樣有問題麼? 就是因為有這樣的疑問,所以就不敢亂寫這篇東西,看了好幾篇部落格,結合書上的例子,看了下百度百科(這個真的強,可能就是用大神的博文做的),最後我得到了這樣的一個理解:抽象工廠要解決的主要問題,是M個不同的產品族,M個產品族都有N個不同的等級,而每個等級的產品,都有共性!!!就是這個共性,才是使用抽象工廠的根本。

什麼意思呢?用上文的程式碼來講述,A系列的車和B系列的車,之所以要把它們分開兩個工廠去實現,抽取出生產車的抽象方法,是因為A系列的車和B系列的車分別有A系列車的共性和B系列車的共性。就比如說,A系列的車在組裝的時候要在方向盤那裡銘一個“A”,B系列的車在組裝的時候要在方向盤那裡銘一個“B”,如果沒用抽象工廠模式,用我上面那段話提的方法,要怎麼實現呢?分別在BenzCarFactory和BmwCarFactory各自實現組裝A字的方法和組裝B字的方法。這樣有啥不好呢?程式碼沒重用唄,因為這兩個方法都是一模一樣的。還有一個問題,假設共性不止一個,而是有很多個,想想是不是很可怕。 而在抽象工廠怎麼實現呢?在ACarFactory直接寫A系列車共性的方法,在BCarFactory直接寫B系列車共性的方法,這樣就很完美了。

然後看完百度百科有點醍醐灌頂的時候,看到了一句話,在日常的程式設計中,工廠方法用得比抽象工廠要多!!!!好吧,給了我一記重錘。

以上,就是我對抽象工廠模式的理解。要打要罵評論區走起。

相關文章