1. 程式人生 > >23種設計模式----工廠方法模式----建立型模式

23種設計模式----工廠方法模式----建立型模式

工廠方法模式或者說是簡單工廠方法。 ps:學會模板方法再學習工廠方法更簡單,或者說工廠方法模式是在模板方法的基礎上進行設計的。

1.什麼是工廠方法模式

將例項的生成交給子類(出自《圖解設計模式》) 這句話怎麼理解? 我自己的理解就是把建立和實現分離。 使用工廠方法,抽象的工廠決定怎麼建立例項,而具體的例項的建立由抽象的工廠的實現去完成。 同樣的的,需要被工廠建立的類也可以抽象為抽象類,抽象類說明這些需要被建立的類的共性,而具體建立的類則是根據需要的抽象類的子類。 很難理解 很難理解 很難理解

2.通俗的解釋

首先建立一個概念: 抽象工廠:決定怎麼建立例項的抽象工廠類 例項工廠:具體執行建立的例項工廠類 抽象產品:需要被建立的類的抽象類共性類 例項產品:真正意義上被建立的類 所以呢,抽象工廠就是使用模板方法的思想。 由抽象的工廠定義建立的方式—關聯抽象產品(模板類) 而例項的工廠實際建立----關聯例項產品(實現類) 所以,這裡又能夠和模板方法對應。

3例子

3.1例子的背景。

車,大家都不陌生。車有自己的屬性,同時每一種車需要有自己的交通規則需要遵守,比如自行車和小汽車,機動車和非機動車。。。。 造車廠,雖然沒有真正的參觀過,但是都聽說過,造車廠裡面的每一種車的建造方式又不相同,有三輪車,小汽車,大巴車。。。。

3.2類的抽象

為了顯示方法的呼叫先後順序等等,建立一個方法類,但是為了增加難度,我們不是使用靜態方法的方式,而是使用繼承的方式:

public class Show {

	public static void show(boolean b,String name){
		System.out.print("#####################################");
		System.out.print(name + (b?"開始":"結束"));
		System.out.println("######################################");
	}
	
}

根據背景。所有的車有一定的共性:一些基本的屬性和需要遵守的交通規則,所以,可以得到車的抽象類

/**
 * 定義車有型別和寬和高三個屬性
 * 定義車的例項建立後,車的屬性無法修改
 * 定義所有的車必須遵守交通規則
 * 設定,預設屬性的全參構造
 */
public abstract class Car extends Show{
	
	private String type;
	
	private Double width;
	
	private Double height;
	
	public Car(String type,Double width,Double height){
		this.type = type;
		this.width = width;
		this.height = height;
	}
	
	public abstract void trafficRuler();

	public String getType() {
		return type;
	}

	public Double getWidth() {
		return width;
	}

	public Double getHeight() {
		return height;
	}
	
}

有了抽象的車,那麼抽象的造車廠也就必須有:

/**
 * 定義一個車的工廠
 * 定義建立車的三個步驟:
 * --doType
 * --doWidth
 * --doHeight
 * 給車定義一個預設的交通規則:靠右行
 */
public abstract class Factory extends Show{
	
	protected abstract void doType();
	
	protected abstract void doWidth();
	
	protected abstract void doHeight();
	
	private Car car;
	
	public Car create(String type,Double width,Double height){
		super.show(true, "Factory#create");
		car = getCar(type,width,height);
		doType();
		doWidth();
		doHeight();
		super.show(false, "Factory#create");
		return car;
	}
	protected abstract Car getCar(String type,Double width,Double height);
}

稍微總結一下。 抽象產品和抽象工廠都有了 在抽象工廠中關聯了抽象產品,需要特別理解的就是為什麼工廠方法是模板方法的基礎上設計的。 在抽象工廠中,使用了一個抽象的方法getCar,這個抽象的方法是在抽象工廠的子類中進行實現的,所以,這裡是一個模板方法的使用。

3.3例項類的抽象

有了抽象的產品和抽象的工廠,接下來就是根據需要,實現例項的工廠個例項的產品。 假設我們需要的車是寶馬車,工廠是寶馬的工廠:

public class BMWCar extends Car{

	public BMWCar(String type, Double width, Double height) {
		super(type, width, height);
	}
	@Override
	public void trafficRuler() {
		super.show(true, "BMWCar#trafficRuler");
		System.out.println("BMWCar#traffic");
		super.show(false, "BMWCar#trafficRuler");
	}

}

寶馬車有自己的三個基本屬性之外,還有自己的交通規則,比如寶馬車只能在公路上行駛,不能再人行道上行駛,不能上天橋。。。。 寶馬車的例項工廠:

public class BMWFactory extends Factory{
	
	private BMWCar bmwCar;
	
	public BMWCar create(String type,Double width,Double height,String carName){
		super.show(true, "Factory#create");
		bmwCar = (BMWCar) getCar(type,width,height);
		doType();
		doWidth();
		doHeight();
		super.show(false, "Factory#create");
		return bmwCar;
	}
	
	
	
	@Override
	protected void doType() {
		super.show(true, "BMWFactory#doType");
		System.out.println("BMW#doType");
		super.show(false, "BMWFactory#doType");
	}

	@Override
	protected void doWidth() {
		super.show(true, "BMWFactory#doWidth");
		System.out.println("BMW#doWidth");
		super.show(false, "BMWFactory#doWidth");
	}

	@Override
	protected void doHeight() {
		super.show(true, "BMWFactory#doHeight");
		System.out.println("BMW#doHeight");
		super.show(false, "BMWFactory#doHeight");
	}
	
	
	@Override
	protected Car getCar(String type,Double width,Double height) {
		return new BMWCar(type,width,height);
	}

}

例項工廠中實現了我們抽象工廠中的getCar的抽象方法,這裡就是模板方法的實現類 同樣呢,可以這麼理解: 抽象工廠建立的是抽象產品 例項工廠建立的是例項產品 抽象和例項是完全分離的 沒有例項,抽象部分也不會報錯,但是不能使用,因為有抽象方法未實現(除非使用內部類的方式實現抽象方法) 例項部分,操作的都是例項相關的變數,和抽象部分沒有關係。實現抽象和例項分離。

3.4測試

具體怎麼使用呢?

public class Main {

	public static void main(String[] args) {

		Factory factory = new BMWFactory();
		BMWCar car = (BMWCar)factory.create("SUV", 2.3, 1.7);
		car.trafficRuler();
	}

}

我們首先需要一個例項工廠,然後傳入引數建立一個例項物件: 所以,首先獲得一個例項的工廠,接下來,建立一個例項物件。 輸出結果:

#####################################Factory#create開始######################################
#####################################BMWFactory#doType開始######################################
BMW#doType
#####################################BMWFactory#doType結束######################################
#####################################BMWFactory#doWidth開始######################################
BMW#doWidth
#####################################BMWFactory#doWidth結束######################################
#####################################BMWFactory#doHeight開始######################################
BMW#doHeight
#####################################BMWFactory#doHeight結束######################################
#####################################Factory#create結束######################################
#####################################BMWCar#trafficRuler開始######################################
BMWCar#traffic
#####################################BMWCar#trafficRuler結束######################################

3.5反思

發現這樣還是沒有什麼變化,甚至複雜化了問題,比如,我們的工廠方法中同樣使用了new的關鍵字,雖然不是直接new一個BMW的物件,但是new了一個BMW的工廠,然後通過工廠來建立的物件。 首先,這樣做有一個好處:模板方法的好處,我們可以在工廠做一些除了建立例項之外的操作,比如對建立的例項進行初始化操作之類的。 第二,我們可以先行定義產品如何建立----模板方法。

4.工廠方法的擴充套件

為什麼使用工廠方法,就是為了更好的擴充套件,使用更加分離的程式碼。 接下來我們的需求是自行車。 首先建立自行車的例項產品:

public class Bike extends Car{

	public Bike(String type, Double width, Double height) {
		super(type, width, height);
	}

	@Override
	public void trafficRuler() {
		super.show(true, "Bike#trafficRuler");
		System.out.println("Bike#traffic");
		super.show(false, "Bike#trafficRuler");
	}

}

接下來是自行車的例項工廠:

public class BikeFactory extends Factory{

	private Bike bike;
	
	public Bike create(String type,Double width,Double height,String carName){
		super.show(true, "Factory#create");
		bike = (Bike) getCar(type,width,height);
		doType();
		doWidth();
		doHeight();
		super.show(false, "Factory#create");
		return bike;
	}
	
	@Override
	protected void doType() {
		super.show(true, "BikeFactory#doType");
		System.out.println("BikeFactory#doType");
		super.show(false, "BikeFactory#doType");
	}

	@Override
	protected void doWidth() {
		super.show(true, "BikeFactory#doWidth");
		System.out.println("BikeFactory#doWidth");
		super.show(false, "BikeFactory#doWidth");
	}

	@Override
	protected void doHeight() {
		super.show(true, "BikeFactory#doHeight");
		System.out.println("BikeFactory#doHeight");
		super.show(false, "BikeFactory#doHeight");
	}

	@Override
	protected Car getCar(String type, Double width, Double height) {
		return new Bike(type, width, height);
	}

}

5測試

測試只需要在之前的測試方法中新增:

//自行車
		factory = new BikeFactory();
		Bike bike = (Bike)factory.create("鳳凰", 0.2, 1.3);
		bike.trafficRuler();

6測試結果

#####################################Factory#create開始######################################
#####################################BMWFactory#doType開始######################################
BMW#doType
#####################################BMWFactory#doType結束######################################
#####################################BMWFactory#doWidth開始######################################
BMW#doWidth
#####################################BMWFactory#doWidth結束######################################
#####################################BMWFactory#doHeight開始######################################
BMW#doHeight
#####################################BMWFactory#doHeight結束######################################
#####################################Factory#create結束######################################
#####################################BMWCar#trafficRuler開始######################################
BMWCar#traffic
#####################################BMWCar#trafficRuler結束######################################
#####################################Factory#create開始######################################
#####################################BikeFactory#doType開始######################################
BikeFactory#doType
#####################################BikeFactory#doType結束######################################
#####################################BikeFactory#doWidth開始######################################
BikeFactory#doWidth
#####################################BikeFactory#doWidth結束######################################
#####################################BikeFactory#doHeight開始######################################
BikeFactory#doHeight
#####################################BikeFactory#doHeight結束######################################
#####################################Factory#create結束######################################
#####################################Bike#trafficRuler開始######################################
Bike#traffic
#####################################Bike#trafficRuler結束######################################

7.問題

進一步反思,發現這樣做還是有問題: 在測試方法中,我們new了不同的例項工廠,我們能不能抽象一個工具類,使用反射的方式來建立例項工廠,因為使用反射,那麼,對於未來抽象工廠所有的子類,我們只需要使用工具類即可。(未實現,後續有機會增加)