设计模式 - 工厂模式
工厂模式(Factory Pattern)是一种创建型设计模式,它通过定义一个用于创建对象的接口,让子类决定实例化哪一个类,从而使得一个类的实例化延迟到子类。工厂模式通过将对象创建的逻辑抽象化,减少了客户端代码与具体类之间的耦合。
工厂模式通常通过工厂类来实现,工厂类负责根据需求创建不同的对象。工厂模式常见的有以下几种变种:
- 简单工厂模式(Simple Factory Pattern)
- 工厂方法模式(Factory Method Pattern)
- 抽象工厂模式(Abstract Factory Pattern)
1. 简单工厂模式
- 定义:
简单工厂模式定义了一个工厂类,它根据不同的输入条件创建不同的产品类实例。客户端通过工厂类来获取所需的对象,而不需要关心对象是如何创建的。
示例:
假设我们有两种产品:ProductA 和 ProductB。客户端通过简单工厂来选择要创建的产品。
-
结构框图
-
代码实现
#include <iostream>// 产品基类
class Product {
public:// 纯虚函数 -> 实现多态(统一抽象化接口)virtual void showProduct() = 0;virtual ~Product() = default;
};// 具体产品A
class ConcreteProductA : public Product {
public:// 重写基类虚函数void showProduct() override {std::cout << "Create Product A" << std::endl;}
};// 具体产品B
class ConcreteProductB : public Product {
public:// 重写基类虚函数void showProduct() override {std::cout << "Create Product B" << std::endl;}
};// 简单工厂类, 用于去创建产品
class SimpleFactory {
public:Product* createProduct(char type) {if (type == 'A') {return new ConcreteProductA();} else if (type == 'B') {return new ConcreteProductB();} else {return nullptr;}}
};int main() {// 通过简单工厂创建产品SimpleFactory myfactory;// 利用简单工厂创建产品AProduct* productA = myfactory.createProduct('A');if(productA){productA->showProduct();}// 利用简单工厂创建产品BProduct* productB = myfactory.createProduct('B');if(productB){productB->showProduct();}delete productA;delete productB;return 1;
}
说明:
- 优点:客户端不需要知道具体类的实现,代码解耦。
- 缺点:随着产品种类的增加,工厂类变得越来越庞大,不符合开闭原则(对修改关闭,对扩展开放)。
2. 工厂方法模式(Factory Method Pattern)
- 定义:
- 封闭-开放 原则:新添加的功能不用去修改以前已经创建的类的内容
工厂方法模式将对象的创建推迟到子类,允许子类决定要创建的对象类型。通过定义一个抽象工厂接口,每个具体工厂只负责创建**一个**
特定类型的对象。
示例:
- 添加一个新的产品,只用新建其对应的产品类以及对于产品工厂类
将简单工厂模式中的产品创建移交给具体工厂类来实现。
-
结构框图
-
代码实现
#include <iostream>class Product
{
public:virtual void showProduct() = 0; // virtual ~Product() = default;
};class ConcreteProductA : public Product {
public:void showProduct() override{std::cout << "A product show (method factory)\n";}
};class ConcreteProductB : public Product {
public:void showProduct() override{std::cout << "B product show (method factory)\n";}
};// 工厂接口
class Factory {
public:virtual Product* createProduct(void) = 0;virtual ~Factory() = default;
};// 具体工厂A接口
class ConcreteFactoryA : public Factory {Product* createProduct(void) override{return new ConcreteProductA;}
};// 具体工厂B接口
class ConcreteFactoryB : public Factory {Product* createProduct(void) override{return new ConcreteProductB;}
};int main()
{Factory* factoryA = new ConcreteFactoryA;Factory* factoryB = new ConcreteFactoryB;Product* productA = factoryA->createProduct();Product* productB = factoryB->createProduct();productA->showProduct();productB->showProduct();delete factoryA;delete factoryB;delete productA;delete productB;return 1;
}
新添加一个产品C只用,添加ConcreteProductC
和ConcreteFactoryC
,但是不用去修改已经存在的类,符合封闭-开放原则的封闭原则。
- 说明:
- 优点:工厂方法模式将创建对象的工作推迟到子类,使得系统易于扩展,可以通过添加新的具体工厂来支持新产品。
- 缺点:每增加一种新产品,都需要增加一个新的工厂类,系统类的数量会迅速增加。
3. 抽象工厂模式(Abstract Factory Pattern)
定义:
抽象工厂模式提供一个接口,用于创建**一系列**
相关或依赖的对象,而无需指定它们具体的类。允许创建一组相关的对象(产品族),而每个具体的工厂都负责创建一组产品。常用于产品族的创建,即一组相互关联的对象的创建(比如跨平台 GUI 界面的不同风格)。
示例:
我们有两种平台(Windows 和 Linux),每个平台有不同的按钮和输入框。抽象工厂模式通过平台工厂来创建相应的控件。
#include <iostream>// 按钮接口
class Button {
public:virtual void render() = 0;virtual ~Button() = default;
};// 输入框接口
class TextField {
public:virtual void render() = 0;virtual ~TextField() = default;
};// 具体按钮类:Windows
class WindowsButton : public Button {
public:void render() override {std::cout << "Rendering Windows Button" << std::endl;}
};// 具体按钮类:Linux
class LinuxButton : public Button {
public:void render() override {std::cout << "Rendering Linux Button" << std::endl;}
};// 具体输入框类:Windows
class WindowsTextField : public TextField {
public:void render() override {std::cout << "Rendering Windows TextField" << std::endl;}
};// 具体输入框类:Linux
class LinuxTextField : public TextField {
public:void render() override {std::cout << "Rendering Linux TextField" << std::endl;}
};// 抽象工厂接口
class GUIFactory {
public:virtual Button* createButton() = 0;virtual TextField* createTextField() = 0;/*父类析构函数为虚函数的原因:在多态情况下正确地执行派生类的析构操作*/virtual ~GUIFactory() = default;
};// 具体工厂类:Windows
class WindowsFactory : public GUIFactory {
public:Button* createButton() override {return new WindowsButton();}TextField* createTextField() override {return new WindowsTextField();}
};// 具体工厂类:Linux
class LinuxFactory : public GUIFactory {
public:Button* createButton() override {return new LinuxButton();}TextField* createTextField() override {return new LinuxTextField();}
};int main() {GUIFactory* factory = new WindowsFactory();Button* button = factory->createButton();TextField* textField = factory->createTextField();button->render(); // 输出: Rendering Windows ButtontextField->render(); // 输出: Rendering Windows TextFielddelete button;delete textField;delete factory;factory = new LinuxFactory();button = factory->createButton();textField = factory->createTextField();button->render(); // 输出: Rendering Linux ButtontextField->render(); // 输出: Rendering Linux TextFielddelete button;delete textField;delete factory;return 0;
}
说明:
- 优点:能够
**创建一系列**
相关的产品,客户端不需要知道具体类的实现,只需依赖工厂接口。 - 缺点:增加了接口和类的数量,如果产品种类过多,抽象工厂可能变得复杂。
4. 工厂方法模式与抽象工厂模式的区别
特性 | 工厂方法模式(Factory Method) | 抽象工厂模式(Abstract Factory) |
---|---|---|
创建对象的方式 | 每个工厂方法只负责创建一个具体产品。 | 创建一系列相关或依赖的产品,通常创建多个产品。 |
产品的数量 | 通常每个工厂类创建一个产品。 | 每个工厂类负责创建多个产品(一个产品族)。 |
工厂的数量 | 每个具体工厂类负责创建一个特定的产品。 | 每个具体工厂类负责创建一系列相关的产品。 |
产品的关系 | 产品之间没有严格的依赖关系。 | 产品之间通常有一定的关联,属于同一个产品族(如同一平台下的按钮和文本框)。 |
扩展性 | 新产品需要新建一个工厂类来负责创建它。 | 新产品族需要新建一个工厂类来创建一组相关产品。 |
适用场景 | 产品种类不多时,或者系统只需要创建单一类型的对象时。 | 当需要创建多个相关产品时,尤其是多个产品属于同一产品族时。 |
总结:
- 工厂方法模式关注于**
单一产品
**的创建,每个具体工厂负责创建一个特定的产品。适用于产品种类少且扩展简单的场景。 - 抽象工厂模式关注于**
一系列相关产品
**的创建,每个具体工厂负责创建多个相关的产品,适用于需要创建多个相关对象并保证它们兼容的场景,如跨平台的 UI 库。
两者的主要区别在于创建产品的数量和产品之间的关系,工厂方法模式偏向于单一产品的创建,而抽象工厂模式偏向于创建一系列相关的产品。