抽象工廠模式仍然屬于創建型模式,我們在【簡單工廠和工廠方法模式】這篇文章中,描述了簡單工廠和工廠方法模式,并在文末,簡單介紹了工廠方法模式的局限性。
本文將通過汽車工廠的例子繼續來闡述使用抽象工廠模式相比較于工廠方法模式的優勢。
文章目錄
- 工廠方法模式回顧
- 抽象工廠模式
- 代碼使用
- 抽象工廠的局限性
工廠方法模式回顧
工廠方法模式通過允許類將實例化延遲到子類中來實現,使得增加新的產品類不需要修改現有系統的代碼。例如,一個汽車制造商需要不同類型的汽車,如寶馬、奧迪等,每種汽車的制造過程可能不同:
#include <iostream>
#include <string>
#include <memory>
using namespace std;class Car {
public:Car(string name) : name_(name) { }virtual ~Car(){}virtual void show() = 0;
protected:string name_;
};class Bmw : public Car {
public:Bmw(string name) : Car(name) { }void show() { cout << "獲得一輛寶馬汽車 " << name_ <<endl; }
};class Audi : public Car {
public:Audi(string name) : Car(name) { }void show() { cout << "獲得一輛奧迪汽車 " << name_ << endl; }
};//工廠方法
class Factory {
public:virtual ~Factory() {}virtual Car* createCar(string name) = 0; //工廠方法
};//寶馬工廠
class BMWFactory : public Factory {
public:Car* createCar(string name) { return new Bmw(name); }
};
//奧迪工廠
class AudiFactory : public Factory {
public:Car* createCar(string name) { return new Audi(name); }
};int main () {unique_ptr<Factory> bmwFactory(new BMWFactory());unique_ptr<Factory> audiFactory(new AudiFactory());unique_ptr<Car> p1(bmwFactory->createCar("X6"));unique_ptr<Car> p2(audiFactory->createCar("A8"));p1->show();p2->show();return 0;
}
現在,我們考慮這樣一種情況,如果我們現在要生產的產品是一組有關聯的產品簇怎么辦?難道我們像工廠方法一樣,又新建立一個工廠來生產該產品嗎?
比如說,我們之前有了奧迪工廠和寶馬工廠,現在我們需要生產奧迪車燈和寶馬車燈,難道又建立奧迪車燈工廠嗎?
這樣的話,最后我們需要管理的工廠(類)那也太多了,所以,很容易想到:
我們應該對一組有關聯關系的產品簇提供產品對象的統一創建。這就是抽象工廠模式。
抽象工廠模式
我們把之前的工廠方法類寫成抽象工廠類,并且里面提供創建車燈的方法,
并且,我們直接在寶馬工廠和奧迪工廠去創建車燈:
//系列產品一:汽車
class Car {
public:Car(string name) : name_(name) { }virtual ~Car(){}virtual void show() = 0;
protected:string name_;
};
class Bmw : public Car {
public:Bmw(string name) : Car(name) { }void show() { cout << "獲得一輛寶馬汽車 " << name_ <<endl; }
};
class Audi : public Car {
public:Audi(string name) : Car(name) { }void show() { cout << "獲得一輛奧迪汽車 " << name_ << endl; }
};
//系列產品二:車燈
class Light {
public:virtual ~Light() {}virtual void show() = 0;
};
class BmwLight : public Light{
public:void show() { cout << "BMW light!" << endl;};
};
class AudiLight : public Light{
public:void show() { cout << "Audi light!" << endl;};
};//工廠方法 =》 抽象工廠(對一組有關聯關系的產品簇提供產品對象的統一創建)
class AbstractFactory {
public:virtual ~AbstractFactory() {}virtual Car* createCar(string name) = 0; //工廠方法 創建汽車virtual Light* createLight() = 0; // 工廠方法 創建汽車關聯的產品--車燈
};//寶馬工廠
class BMWFactory : public AbstractFactory {
public:Car* createCar(string name) { return new Bmw(name); }Light* createLight() {return new BmwLight();}
};
//奧迪工廠
class AudiFactory : public AbstractFactory {
public:Car* createCar(string name) { return new Audi(name); }Light* createLight() {return new AudiLight();}
};
代碼使用
int main () {unique_ptr<AbstractFactory> bmwFactory(new BMWFactory());unique_ptr<AbstractFactory> audiFactory(new AudiFactory());unique_ptr<Car> p1(bmwFactory->createCar("X6"));unique_ptr<Car> p2(audiFactory->createCar("A8"));unique_ptr<Light> l1(bmwFactory->createCarLight());unique_ptr<Light> l2(audiFactory->createCarLight());p1->show();l1->show();p2->show();l2->show();return 0;
}
抽象工廠的局限性
我們設想這樣一種場景,比如說我們的寶馬工廠需要創建一個新的類對象(產品),但是奧迪工廠并不需要,但是如果寶馬工廠想要創建該類,
我們也比賽在抽象工廠類中去定義這樣一個虛函數,盡管奧迪工廠并不需要創建該類對象,他還是不得不去重寫該虛函數。這樣是不符合邏輯的。
總結:
簡單工廠Simple Factory:
優點:把對象的創建封裝在一個接口函數里面,通過傳入不同的標識,返回創建的對象,用戶不用自己負責new對象,不用了解對象創建的詳細過程
缺點:提供創建對象實例的接口函數不閉合,不能對修改關閉
工廠方法Factory Method:
優點:Fatcory基類,提供了一個純虛函數(創建產品),定義派生類(具體產品的工廠)負責創建對應的產品,可以做到不同的產品,在不同的工廠里面創建,能夠對現有工廠,以及產品的修改關閉
缺點:實際上,很多產品是有管理關系的,屬于一個產品簇,不應該放在不同的工廠里面去創建,這樣一是不符合實際的產品對象創建邏輯,二是工廠類太多了,不好維護
抽象工廠Abstract Factory
優點:把有關聯關系的,屬于一個產品簇的所有產品創建的接口函數,放在一個抽象工廠里面AbstractFactory類,派生類(具體產品的工廠)應該負責創建該產品簇里面所有的產品。