首先了解一下什么是工厂方法模式?
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它提供了一种方法来封装对象的创建逻辑。具体来说,它通过定义一个创建对象的接口(即工厂方法),但将具体的对象实例化工作推迟到子类中完成。这样,客户端代码可以在不知道具体类的情况下创建对象,从而实现创建与使用的分离。
作用
工厂方法模式在软件设计中有以下几个主要作用:
-
解耦:
将对象的创建与使用分离,客户端无需了解具体类的实现细节,只需通过工厂方法获取对象即可。这降低了代码的耦合度。 -
扩展性:
当需要添加新的对象类型时,只需增加新的具体工厂类和产品类,而无需修改现有代码,符合之前我们提到的“开闭原则”(对扩展开放,对修改关闭)(SOLID的O)。 -
灵活性:
通过工厂方法,系统可以在运行时动态决定实例化哪个类,增加了程序的灵活性。
用法
工厂方法模式适用于以下场景:
- 当一个类无法预先知道需要创建的具体对象类型时。
- 当希望由子类决定创建哪种对象时。
- 当需要将对象的创建职责委托给多个子类中的某一个时。
C++ 示例
下面通过一个完整的 C++ 示例来说明工厂方法模式。我们以创建不同类型车辆(汽车和卡车)为例。
具体的UML图如下:
1. 定义产品接口
首先,定义一个抽象基类 Vehicle
,它声明了所有车辆必须实现的方法。
#include <iostream>class Vehicle {
public:virtual void drive() const = 0; // 纯虚函数,所有子类必须实现virtual ~Vehicle() = default; // 虚析构函数,确保正确释放资源
};
2. 实现具体产品类
接下来,创建两个具体产品类 Car
和 Truck
,它们继承自 Vehicle
,并实现 drive
方法。
class Car : public Vehicle {
public:void drive() const override {std::cout << "Driving a car." << std::endl;}
};class Truck : public Vehicle {
public:void drive() const override {std::cout << "Driving a truck." << std::endl;}
};
3. 定义工厂接口
然后,定义一个抽象工厂类 VehicleFactory
,它包含一个纯虚函数 createVehicle
,用于创建 Vehicle
对象的实例。
class VehicleFactory {
public:virtual Vehicle* createVehicle() const = 0; // 工厂方法,子类必须实现virtual ~VehicleFactory() = default; // 虚析构函数
};
4. 实现具体工厂类
再创建两个具体工厂类 CarFactory
和 TruckFactory
,它们继承自 VehicleFactory
,并实现 createVehicle
方法,分别返回 Car
和 Truck
实例。
class CarFactory : public VehicleFactory {
public:Vehicle* createVehicle() const override {return new Car();}
};class TruckFactory : public VehicleFactory {
public:Vehicle* createVehicle() const override {return new Truck();}
};
5. 使用工厂方法
在客户端代码中,通过工厂对象创建车辆实例,而无需直接实例化具体类。
int main() {// 创建汽车工厂并生产汽车VehicleFactory* carFactory = new CarFactory(); //注意这里含有纯虚函数的抽象类,是不可以初始化的,但是它的指针可以接受子类new出来的对象Vehicle* car = carFactory->createVehicle();car->drive(); // 输出: Driving a car.delete car; // 释放车辆对象delete carFactory; // 释放工厂对象// 创建卡车工厂并生产卡车VehicleFactory* truckFactory = new TruckFactory();Vehicle* truck = truckFactory->createVehicle();truck->drive(); // 输出: Driving a truck.delete truck; // 释放车辆对象delete truckFactory; // 释放工厂对象return 0;
}
运行以上代码,输出如下:
Driving a car.
Driving a truck.
详细解释
让我们逐步分析这个示例的每个组成部分:
-
产品接口(Vehicle)
Vehicle
是一个抽象基类,定义了所有具体产品(Car
和Truck
)必须实现的接口(drive
方法)。- 使用纯虚函数(
= 0
)确保子类必须提供实现。 - 虚析构函数确保通过基类指针删除对象时能正确释放资源。
-
具体产品(Car、Truck)
Car
和Truck
是具体的产品类,继承自Vehicle
,并实现了drive
方法。- 它们代表系统中实际的对象类型,提供了具体的功能实现。
-
工厂接口(VehicleFactory)
VehicleFactory
是一个抽象工厂类,定义了工厂方法createVehicle
。- 该方法是纯虚的,意味着具体工厂类必须实现它来创建具体产品。
-
具体工厂(CarFactory、TruckFactory)
CarFactory
和TruckFactory
是具体工厂类,分别负责创建Car
和Truck
对象。- 通过重写
createVehicle
,它们封装了对象的创建逻辑。
-
客户端代码
- 客户端通过
VehicleFactory
接口调用createVehicle
方法来创建对象。 - 客户端无需知道具体的产品类(
Car
或Truck
)或其实现细节,只需与工厂交互即可。 - 这种方式实现了创建与使用的解耦。
- 客户端通过
模式优势
- 解耦:客户端代码不直接依赖具体产品类(
Car
或Truck
),而是通过工厂接口操作。 - 扩展性:如果需要添加新的车辆类型(如
Motorcycle
),只需新增Motorcycle
类和对应的MotorcycleFactory
类,无需修改现有代码。 - 灵活性:可以在运行时根据需要选择不同的工厂,动态创建不同类型的对象。
总结
工厂方法模式通过将对象的创建逻辑封装在子类中,实现了对象创建与使用的分离。它在 C++ 中通过抽象工厂类和具体工厂类的配合,提供了灵活、可扩展的创建机制。在上述示例中,我们通过创建车辆的工厂方法模式展示了其核心思想:定义接口,推迟实现,解耦使用。这种模式特别适合需要动态创建多种对象类型的场景,是设计模式中非常实用的一种方法。