想像你走進一間特斯拉汽車工廠,這裡的工廠並不只是為了生產一款車型,而是可以生產多種不同的車型,像是Model 3、Model Y、Model S、Model X。每個車型雖然都有自己獨特的設計和功能,但它們都有一個共同的特點:它們都是特斯拉生產的。這種情境正好反映了工廠方法模式 Factory Method Pattern 的應用。
工廠方法模式是一種建立型設計模式,透過定義一個建立物件的介面來讓子類決定實例化哪一個類別。也就是說工廠方法將物件的建立過程延遲到子類別進行,當我們需要新增車款時,只需建立新的車款子類別,而不必改現有的類別程式碼,從而達成開放封閉原則。在工廠模式中,我們在建立物件時不會對客戶端暴露建立邏輯,而是透過使用一個共同的介面來指向新建立的物件。
工廠模式的核心思想是:『把物件的建立過程封裝起來,使得客戶端(使用者)不需要關心具體物件是如何建立的,只需透過工廠來取得所需的物件。』這樣不僅減少了客戶端的複雜度,也增加了系統的靈活性,因為我們可以輕鬆地改變建立物件的方式,而不影響使用者的程式碼。
接下來我們將用工廠方法模式來模擬特斯拉工廠如何生產不同的車款。
在工廠方法模式中通常會有以下幾個角色:
Product(產品):定義了工廠方法所建立的物件的介面。
ConcreteProduct(具體產品):實現了 Product 介面,具體化了不同車款的類別。
Creator(建立者):宣告了工廠方法,該方法回傳 Product 物件。Creator 的子類別將實現這個方法, 來建立具體的產品物件。
ConcreteCreator(具體建立者):實現 Creator 介面並定義具體工廠方法來建立不同的車款。
首先定義一個通用的汽車介面(Product),
// 汽車介面
class Car {
public:
virtual void drive() = 0;
virtual ~Car() {}
};
我們為每一款車建立具體產品類別(ConcreteProduct),
// 具體產品類別 Model3
class Model3 : public Car {
public:
void drive() override {
std::cout << "Driving a Tesla Model 3.\n";
}
};
// 具體產品類別 ModelY
class ModelY : public Car {
public:
void drive() override {
std::cout << "Driving a Tesla Model Y.\n";
}
};
// 具體產品類別 ModelS
class ModelS : public Car {
public:
void drive() override {
std::cout << "Driving a Tesla Model S.\n";
}
};
// 具體產品類別 ModelX
class ModelX : public Car {
public:
void drive() override {
std::cout << "Driving a Tesla Model X.\n";
}
};
再來定義建立者(Creator)和具體建立者(ConcreteCreator),
// 建立者介面
class CarFactory {
public:
virtual std::unique_ptr<Car> createCar() = 0;
virtual ~CarFactory() {}
};
// 具體建立者:Model 3 工廠
class Model3Factory : public CarFactory {
public:
std::unique_ptr<Car> createCar() override {
return std::make_unique<Model3>();
}
};
// 具體建立者:Model Y 工廠
class ModelYFactory : public CarFactory {
public:
std::unique_ptr<Car> createCar() override {
return std::make_unique<ModelY>();
}
};
// 具體建立者:Model S 工廠
class ModelSFactory : public CarFactory {
public:
std::unique_ptr<Car> createCar() override {
return std::make_unique<ModelS>();
}
};
// 具體建立者:Model X 工廠
class ModelXFactory : public CarFactory {
public:
std::unique_ptr<Car> createCar() override {
return std::make_unique<ModelX>();
}
};
現在我們可以使用這些工廠來生產不同的車款,
int main() {
// 建立各個車型的工廠
std::unique_ptr<CarFactory> model3Factory = std::make_unique<Model3Factory>();
std::unique_ptr<CarFactory> modelYFactory = std::make_unique<ModelYFactory>();
std::unique_ptr<CarFactory> modelSFactory = std::make_unique<ModelSFactory>();
std::unique_ptr<CarFactory> modelXFactory = std::make_unique<ModelXFactory>();
// 產生 Model 3
std::unique_ptr<Car> model3 = model3Factory->createCar();
model3->drive();
// 產生 Model Y
std::unique_ptr<Car> modelY = modelYFactory->createCar();
modelY->drive();
// 產生 Model S
std::unique_ptr<Car> modelS = modelSFactory->createCar();
modelS->drive();
// 產生 Model X
std::unique_ptr<Car> modelX = modelXFactory->createCar();
modelX->drive();
return 0;
}
在這個範例中每個 CarFactory 子類別負責建立特定車型的汽車,工廠方法 createCar() 回傳一個 Car 物件。這樣的設計讓我們能夠輕鬆地新增或修改車型,而不必更改主程式的邏輯。
工廠方法模式最大的體現在於客戶端無需直接接觸實際的產品類別,以這個例子為例,客戶端不需直接去 new Model3 這個 class,這個 Model3 class 就放在工廠內部的實現就好,這樣解耦客戶端與具體產品類別之間的依賴關係。這樣客戶端的程式碼不會因為產品類別的改變而受到影響,這就是工廠方法模式提供的高度靈活性和可擴展性。
工廠方法模式有不少好處,像是當我們需要新增車款時,不需要動到現有的程式碼,只需新增一個相應的工廠類別就可以了,這樣一來系統變得更靈活,也更符合開放封閉原則。另外工廠方法模式還能讓產品的產生與使用分離開來,這樣做的好處是減少了系統內部的耦合,讓程式碼更容易維護和擴展。
工廠方法模式也有它的缺點。因為每新增一款車,就要寫一個新的工廠類別,久而久之類別的數量會不斷增加,讓程式碼結構變得複雜,管理起來也會變得麻煩。這樣的代價在某些系統中可能會造成不便,特別是當產品種類多而需求變化頻繁的時候。
工廠方法模式在需要靈活建立不同產品的系統中非常有用,但也需要考慮到它可能帶來的複雜性,衡量是否適合使用。
工廠方法模式它允許我們根據需求建立不同的產品物件。在這篇文章中我們透過特斯拉汽車工廠的範例,展示了如何使用工廠方法模式來靈活地產生 Model 3、Model Y、Model S 和 Model X 等不同的車款。這種模式不僅提高了系統的靈活性和可擴展性,還降低了系統的耦合度。
設計模式是解決問題的工具,而不是目的本身。靈活運用才能寫出真正優雅且實用的程式碼。就像一個熟練的廚師,知道何時使用何種工具來製作最美味的菜餚,一個優秀的程式設計師也應該知道何時使用何種設計模式來創造出最優雅的程式碼。
更多C++語言相關的文章,歡迎追蹤我的部落格。
https://shengyu7697.github.io/cpp-factory-method-pattern/