設計模式--工廠模式 ➪〖 簡單工廠模式+工廠方法模式 〗

工廠模式的概念:
  1. 實例化對象,用工廠方法替代new操作,避免你辛苦的準備構造方法的參數
  2. 工廠模式包括工廠方法模式和抽象工廠模式
  3. 抽象工廠模式是工廠方法模式的拓展
  4. 工廠對象可以被傳遞


工廠模式的意義:
  1. 在面向對象編程中, 最通常的方法是一個new操作符產生一個對象實例,new操作符就是用來構造對象實例的。但是在一些情況下, new操作符直接生成對象會帶來一些問題。舉例來說, 許多類型對象的創造需要一系列的步驟:你可能需要計算或取得對象的初始設置; 選擇生成哪個子對象實例; 或在生成你需要的對象之前必須先生成一些輔助功能的對象(即創建對象的過程複雜繁瑣)。 在這些情況下,新對象的建立就是一個 “過程”,不僅是一個操作。
  2. 如果需要客戶端來創建對象的話,一旦服務端的該類發生改變(例如本來的構造函數失效了),就會在客戶端造成嚴重的問題,所以我們應該鬆耦合,把創建對象的過程交給服務端,客戶端直接取就可以了。

比喻:
  1. 還沒有工廠時代:假如還沒有工業革命,如果一個客戶要一款奧迪車,一般的做法是客戶去創建一款奧迪車,然後拿來用。
  2. 簡單工廠模式:後來出現工業革命。用戶不用去創建奧迪車。因爲客戶有一個工廠來幫他創建奧迪車.想要什麼車,這個工廠就可以建。比如想要A系列車。工廠就創建這個系列的車。即工廠可以創建產品。
  3. 工廠方法模式:爲了滿足客戶,奧迪車系列越來越多,如A系列,R系列一個工廠無法創建所有的奧迪系列。於是由單獨分出來多個具體的工廠。每個具體工廠創建一種系列。即具體工廠類只能創建一個具體產品。但是奧迪工廠還是個抽象。你需要指定某個具體的工廠才能生產車出來。
  4. 抽象工廠模式:隨着客戶的要求越來越高,奧迪車必須配置空調。於是這個工廠開始生產奧迪車和需要的空調。


簡單工廠模式:

我們先以造奧迪車A系車來舉例。首先我們需要先定義一個空的接口類Car一個接口類Audi_A,且繼承了接口類Car,並且聲明三個簡單的方法
public interface Car {
}
public interface Audi_A extends Car{
	//顯示車輛價格
	public String luxury();
	//顯示最高車速
	public String walk();
	//顯示車輛基本參數
	public String show();
}

然後我們創建一個實現Audi_A接口的實體類Audi_A4,類裏聲明瞭兩個簡單的價格,車速屬性並且賦值,以及兩個構造方法,並且實現接口中的三個方法。
public class Audi_A4 implements Audi_A{
	
	private int speed = 180;
	private int price = 25;
	
	public Audi_A4() {
		System.out.println("這是一輛普通的Audi_A4");
	}
	public Audi_A4( int speed, int price) {
		System.out.println("這是一輛定製版的Audi_A4");
		this.speed = speed;
		this.price = price;
	}
	
	@Override
	public String walk() {
		// TODO Auto-generated method stub
		return "Audi_A4 速度是:" + speed  + "km/s";
	}

	@Override
	public String luxury() {
		// TODO Auto-generated method stub
		return "Audi_A4 的價格是:" + price + "w";
	}

	@Override
	public String show() {
		// TODO Auto-generated method stub
		return walk() + "\n" + luxury();
	}

}
接着我們創建一個汽車工廠接口FactoryInterface,聲明瞭三個生產汽車的方法:
public interface FactoryInterface {
	/**
	 * @方法描述:生產組裝標準車
	 * @創建時間:2017年7月20日下午6:15:34
	 */
	public Car ProduceCar_original(String id);
	
	
	/**
	 * @方法描述:生成經過客戶特別定製的車
	 * @創建時間:2017年7月20日下午6:16:35
	 */
	public Car ProduceCar_vip(String id,int speed,int price);
	
	/**
	 * @方法描述:生產經過工廠調整配置的標準車
	 * @創建時間:2017年7月20日下午6:17:15
	 */
	public Car ProduceCar_Facotry(String id);

}
     接着我們創建一個專門生產奧迪A系的汽車工廠Audi_A_Factory,並且該類實現了工廠接口
public class Audi_A_Factory implements FactoryInterface{
	
	/**
	 * @方法描述:生產組裝標準車
	 * @創建時間:2017年7月20日下午6:15:34
	 */
	@Override
	public Audi_A ProduceCar_original(String id) {
			Audi_A audiCar = new Audi_A4();
			return audiCar;
	}
	@Override
	public Audi_A ProduceCar_vip(String id, int speed, int price) {
		return null;
	}

	@Override
	public Audi_A ProduceCar_Facotry(String id) {
		return null;
	}

}
下面我們就可以利用工廠類來獲得一輛Audi_A4了,但是這個也太容易了,如果這個時候我們需要一輛Audi_A6或者A7,A8呢?我們當然可以在工廠類裏面用switch分支語句來選擇new其他型號車輛,有沒有更好的辦法呢?我們可以利用Java的反射機制動態創建對象,我們需要改寫Audi_A_Factory類中的ProduceCar_original方法:
@Override
	public Audi_A ProduceCar_original(String id) {
			try {
				Audi_A audiCar = (Audi_A)Class.forName(id).newInstance();
				 return audiCar;
			} catch (ClassNotFoundException |  SecurityException |InstantiationException | IllegalAccessException | IllegalArgumentException
					 e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return null;
	}
此時我們就可以動態生成任何實現了Audi_A接口的奧迪A系車了,我們創建一個叫Audi_A6的類並實現Audi_A接口
public class Audi_A6 implements Audi_A{
	private int speed = 200;
	private int pirce = 50;
	
	public Audi_A6() {
		System.out.println("這是一輛普通的Audi_A6");
	}
	public Audi_A6(int speed, int pirce) {
		System.out.println("這是一輛定製版的Audi_A6");
		this.speed = speed;
		this.pirce = pirce;
	}
	@Override
	public String walk() {
		return "Audi_A6 速度是:" + speed + "km/s";
	}
	@Override
	public String luxury() {
		return "Audi_A6 的價格是:" + pirce + "w";
	}
	@Override
	public String show() {
		return walk() + "\n" + luxury();
	}
}
編寫一個測試類,並在ProduceCar_original方法中傳入Audi_A6的全類名:
public class Test {
	public static void main(String[] args) {
		Audi_A_Factory audiFactory = new Audi_A_Factory();
		Audi_A audi_Car = audiFactory.ProduceCar_original("FactoryBean.Audi_A6");
		System.out.println(audi_Car.show());
	}
}
我們可以看到結果打印爲:
這是一輛普通的Audi_A6
Audi_A6 速度是:200km/s
Audi_A6 的價格是:50w
 通過傳入全類名的方式,我們可以利用反射的到類的實例,通過這樣的方式我們就可以做到不修改工廠代碼就能生產出其他型號的A 系車。
 此時我們出現了一個情況因爲BMW的裝配平臺升級,Audi_A4銷量下降了,於是我們決定降低Audi_A4的價格,可是我們可能無法直接修改Audi_A4類裏的屬性,我們需要在工廠中利用構造參數統一調整價格,我們改寫Audi_A_Factory類中的ProduceCar_Facotry方法:
@Override
	public Audi_A ProduceCar_Facotry(String id) {
		Audi_A audi_A;
		switch (id) {
			case "FactoryBean.Audi_A4":audi_A = new Audi_A4(190,50); break;
			case "FactoryBean.Audi_A6":audi_A = new Audi_A6(220, 45); break;
			default:audi_A = ProduceCar_original(id); break;
		}
		return audi_A;
	}
隨着市場競爭越來越激烈,Audi工廠推出了可以讓用戶自己指定價格和性能的車,那我們需要改寫Audi_A_Factory類中的ProduceCar_vip方法,同樣的我們使用反射來生產用戶定製的車子(這裏注意反射的用法,因爲需要傳參):
@Override
	public Audi_A ProduceCar_vip(String id, int speed, int price) {
		// TODO Auto-generated method stub
		try {
			 Class<?> cls = Class.forName(id);
			 Constructor<?> cons = cls.getDeclaredConstructor(int.class,int.class);
			 cons.setAccessible(true);
			 Audi_A audiCar = (Audi_A)cons.newInstance(speed,price);
			 return audiCar;
		} catch (ClassNotFoundException | NoSuchMethodException | SecurityException |InstantiationException | IllegalAccessException | IllegalArgumentException
				| InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
我們在測試類中進行測試:
public class Test {
	public static void main(String[] args) {
		Audi_A_Factory audiFactory = new Audi_A_Factory();
		Audi_A audi_Car = audiFactory.ProduceCar_vip("FactoryBean.Audi_A6", 300, 200);
		System.out.println(audi_Car.show());
	}
}
可以看到輸出爲:
這是一輛定製版的Audi_A6
Audi_A6 速度是:300km/s
Audi_A6 的價格是:200w
看到這裏想必你一定對簡單工廠模式有了一個很詳細的瞭解,而工廠方法模式則相當於我們再創建一個工廠類生產Audi的X系車,但是仍然需要實現FactoryInterface即抽象工廠接口,這個時候再看一遍前面工廠模式的意義:

工廠模式的意義:
  1. 在面向對象編程中, 最通常的方法是一個new操作符產生一個對象實例,new操作符就是用來構造對象實例的。但是在一些情況下, new操作符直接生成對象會帶來一些問題。舉例來說, 許多類型對象的創造需要一系列的步驟: 你可能需要計算或取得對象的初始設置; 選擇生成哪個子對象實例; 或在生成你需要的對象之前必須先生成一些輔助功能的對象(即創建對象的過程複雜繁瑣)。 在這些情況,新對象的建立就是一個 “過程”,不僅是一個操作。
  2. 如果需要客戶端來創建對象的話,一旦服務端的該類發生改變(例如本來的構造函數失效了),就會在客戶端造成嚴重的問題,所以我們應該鬆耦合,把創建對象的過程交給服務端,客戶端直接取就可以了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章