- 實例化對象,用工廠方法替代new操作,避免你辛苦的準備構造方法的參數
- 工廠模式包括工廠方法模式和抽象工廠模式
- 抽象工廠模式是工廠方法模式的拓展
- 工廠對象可以被傳遞
- 在面向對象編程中, 最通常的方法是一個new操作符產生一個對象實例,new操作符就是用來構造對象實例的。但是在一些情況下, new操作符直接生成對象會帶來一些問題。舉例來說, 許多類型對象的創造需要一系列的步驟:你可能需要計算或取得對象的初始設置; 選擇生成哪個子對象實例; 或在生成你需要的對象之前必須先生成一些輔助功能的對象(即創建對象的過程複雜繁瑣)。 在這些情況下,新對象的建立就是一個 “過程”,不僅是一個操作。
- 如果需要客戶端來創建對象的話,一旦服務端的該類發生改變(例如本來的構造函數失效了),就會在客戶端造成嚴重的問題,所以我們應該鬆耦合,把創建對象的過程交給服務端,客戶端直接取就可以了。
- 還沒有工廠時代:假如還沒有工業革命,如果一個客戶要一款奧迪車,一般的做法是客戶去創建一款奧迪車,然後拿來用。
- 簡單工廠模式:後來出現工業革命。用戶不用去創建奧迪車。因爲客戶有一個工廠來幫他創建奧迪車.想要什麼車,這個工廠就可以建。比如想要A系列車。工廠就創建這個系列的車。即工廠可以創建產品。
- 工廠方法模式:爲了滿足客戶,奧迪車系列越來越多,如A系列,R系列一個工廠無法創建所有的奧迪系列。於是由單獨分出來多個具體的工廠。每個具體工廠創建一種系列。即具體工廠類只能創建一個具體產品。但是奧迪工廠還是個抽象。你需要指定某個具體的工廠才能生產車出來。
- 抽象工廠模式:隨着客戶的要求越來越高,奧迪車必須配置空調。於是這個工廠開始生產奧迪車和需要的空調。
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
系車。@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
- 在面向對象編程中, 最通常的方法是一個new操作符產生一個對象實例,new操作符就是用來構造對象實例的。但是在一些情況下, new操作符直接生成對象會帶來一些問題。舉例來說, 許多類型對象的創造需要一系列的步驟: 你可能需要計算或取得對象的初始設置; 選擇生成哪個子對象實例; 或在生成你需要的對象之前必須先生成一些輔助功能的對象(即創建對象的過程複雜繁瑣)。 在這些情況,新對象的建立就是一個 “過程”,不僅是一個操作。
- 如果需要客戶端來創建對象的話,一旦服務端的該類發生改變(例如本來的構造函數失效了),就會在客戶端造成嚴重的問題,所以我們應該鬆耦合,把創建對象的過程交給服務端,客戶端直接取就可以了。