设计模式 - 工厂模式
工厂模式(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;
// 利用简单工厂创建产品A
Product* productA = myfactory.createProduct('A');
if(productA)
{
productA->showProduct();
}
// 利用简单工厂创建产品B
Product* 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 Button
textField->render(); // 输出: Rendering Windows TextField
delete button;
delete textField;
delete factory;
factory = new LinuxFactory();
button = factory->createButton();
textField = factory->createTextField();
button->render(); // 输出: Rendering Linux Button
textField->render(); // 输出: Rendering Linux TextField
delete button;
delete textField;
delete factory;
return 0;
}
说明:
- 优点:能够
**创建一系列**
相关的产品,客户端不需要知道具体类的实现,只需依赖工厂接口。 - 缺点:增加了接口和类的数量,如果产品种类过多,抽象工厂可能变得复杂。
4. 工厂方法模式与抽象工厂模式的区别
特性 | 工厂方法模式(Factory Method) | 抽象工厂模式(Abstract Factory) |
---|---|---|
创建对象的方式 | 每个工厂方法只负责创建一个具体产品。 | 创建一系列相关或依赖的产品,通常创建多个产品。 |
产品的数量 | 通常每个工厂类创建一个产品。 | 每个工厂类负责创建多个产品(一个产品族)。 |
工厂的数量 | 每个具体工厂类负责创建一个特定的产品。 | 每个具体工厂类负责创建一系列相关的产品。 |
产品的关系 | 产品之间没有严格的依赖关系。 | 产品之间通常有一定的关联,属于同一个产品族(如同一平台下的按钮和文本框)。 |
扩展性 | 新产品需要新建一个工厂类来负责创建它。 | 新产品族需要新建一个工厂类来创建一组相关产品。 |
适用场景 | 产品种类不多时,或者系统只需要创建单一类型的对象时。 | 当需要创建多个相关产品时,尤其是多个产品属于同一产品族时。 |
总结:
- 工厂方法模式关注于**
单一产品
**的创建,每个具体工厂负责创建一个特定的产品。适用于产品种类少且扩展简单的场景。 - 抽象工厂模式关注于**
一系列相关产品
**的创建,每个具体工厂负责创建多个相关的产品,适用于需要创建多个相关对象并保证它们兼容的场景,如跨平台的 UI 库。
两者的主要区别在于创建产品的数量和产品之间的关系,工厂方法模式偏向于单一产品的创建,而抽象工厂模式偏向于创建一系列相关的产品。