简单工厂模式,工厂模式和注册工厂模式
简单工厂模式(Simple Factory Pattern)
- 定义:又称静态工厂模式,通过一个工厂类根据传入的参数,返回对应类的实例。它并非 GOF 标准设计模式,而是一种编程习惯。
- 核心角色:
- 工厂类:包含静态方法,根据参数创建产品实例。
- 抽象产品:定义产品公共接口。
- 具体产品:实现产品接口的具体类。
简单工厂模式(Simple Factory Pattern)属于创建型设计模式,它通过一个工厂类决定创建哪一种产品类的实例,而不需要直接使用 new
运算符实例化对象。该模式将对象的创建逻辑封装在一个单独的类中,客户端只需知道所需产品的类型即可。
代码展示
#include <iostream>
#include <string>// 抽象产品:汽车接口
class Car {
public:virtual void drive() = 0;virtual ~Car() = default;
};// 具体产品:轿车
class Sedan : public Car {
public:void drive() override {std::cout << "驾驶轿车" << std::endl;}
};// 具体产品:SUV
class SUV : public Car {
public:void drive() override {std::cout << "驾驶SUV" << std::endl;}
};// 简单工厂:根据类型创建汽车
class CarFactory {
public:// 静态方法,根据参数返回不同产品static Car* createCar(const std::string& type) {if (type == "sedan") {return new Sedan();} else if (type == "suv") {return new SUV();} else {throw std::invalid_argument("未知车型");}}
};// 客户端代码
int main() {Car* sedan = CarFactory::createCar("sedan");sedan->drive(); // 输出:驾驶轿车Car* suv = CarFactory::createCar("suv");suv->drive(); // 输出:驾驶SUVdelete sedan;delete suv;return 0;
}
缺点也很明显,代码不易拓展。每当我要添加新产品时,我都要修改工厂类,违反了开闭原则(对拓展开放,对修改关闭)。
工厂方法模式(Factory Method Pattern)
- 定义:定义一个创建对象的接口,但由子类决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类。
- 核心角色:
- 抽象工厂(Creator):声明创建对象的接口。
- 具体工厂(ConcreteCreator):实现工厂接口,创建具体产品。
- 抽象产品(Product):定义产品的公共接口。
- 具体产品(ConcreteProduct):实现产品接口的具体类。
代码展示
#include <iostream>
#include <string>// 抽象产品:汽车接口
class Car {
public:virtual void drive() = 0;virtual ~Car() = default;
};// 具体产品:轿车
class Sedan : public Car {
public:void drive() override {std::cout << "驾驶轿车" << std::endl;}
};// 具体产品:SUV
class SUV : public Car {
public:void drive() override {std::cout << "驾驶SUV" << std::endl;}
};// 抽象工厂:声明创建汽车的接口
class CarFactory {
public:virtual Car* createCar() = 0;virtual ~CarFactory() = default;
};// 具体工厂:创建轿车
class SedanFactory : public CarFactory {
public:Car* createCar() override {return new Sedan();}
};// 具体工厂:创建SUV
class SUVFactory : public CarFactory {
public:Car* createCar() override {return new SUV();}
};// 客户端代码
int main() {// 通过具体工厂创建对象CarFactory* sedanFactory = new SedanFactory();Car* sedan = sedanFactory->createCar();sedan->drive(); // 输出:驾驶轿车CarFactory* suvFactory = new SUVFactory();Car* suv = suvFactory->createCar();suv->drive(); // 输出:驾驶SUVdelete sedan;delete suv;delete sedanFactory;delete suvFactory;return 0;
}
缺点:虽然添加新的项很容易,但它将创建对象的逻辑丢给了客户端,又失去了简单工厂模式里仅通过几个参数就可以简单的创建一个对象。要解决工厂模式中 “客户端需直接与具体工厂交互” 的问题,同时保留其扩展性优势,可以结合注册式工厂(Registry-based Factory)或动态工厂(Dynamic Factory)的设计思路。这类方案通过集中管理工厂映射,让客户端仅需传递简单参数(如类型名、标识符)即可创建对象,同时保持对开闭原则的支持。
解决方案:注册式工厂(Registry-based Factory)
通过全局工厂注册表管理类型名称与具体工厂的映射关系。客户端仅需传递类型名称,工厂类自动查找对应的具体工厂并创建对象。新增产品时,只需向注册表注册新的工厂类,无需修改现有代码。
核心思路
- 定义统一注册接口:所有具体工厂需实现该接口,以便注册到全局注册表。
- 维护工厂映射表:用哈希表(如
std::unordered_map
)存储类型名称与工厂实例的映射。 - 动态创建对象:客户端通过类型名称调用工厂方法,工厂类从映射表中查找对应工厂并创建对象。
代码展示
#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <stdexcept>// ------------------------- 抽象产品与具体产品 -------------------------
class Car {
public:virtual void drive() = 0;virtual ~Car() = default;
};class Sedan : public Car {
public:void drive() override { std::cout << "驾驶轿车" << std::endl; }
};class SUV : public Car {
public:void drive() override { std::cout << "驾驶SUV" << std::endl; }
};// 新增产品:Truck(后续扩展时无需修改现有代码)
class Truck : public Car {
public:void drive() override { std::cout << "驾驶卡车" << std::endl; }
};// ------------------------- 抽象工厂与具体工厂 -------------------------
class CarFactory {
public:virtual Car* create() = 0;virtual ~CarFactory() = default;
};// 具体工厂:SedanFactory
class SedanFactory : public CarFactory {
public:Car* create() override { return new Sedan(); }
};// 具体工厂:SUVFactory
class SUVFactory : public CarFactory {
public:Car* create() override { return new SUV(); }
};// 具体工厂:TruckFactory(新增产品对应的工厂)
class TruckFactory : public CarFactory {
public:Car* create() override { return new Truck(); }
};// ------------------------- 注册式主工厂 -------------------------
class GlobalCarFactory {
private:// 全局工厂映射表:类型名称 → 工厂实例static std::unordered_map<std::string, std::unique_ptr<CarFactory>> factoryRegistry;public:// 注册工厂到全局表中static void registerFactory(const std::string& type, std::unique_ptr<CarFactory> factory) {factoryRegistry[type] = std::move(factory);}// 根据类型名称创建汽车对象static std::unique_ptr<Car> createCar(const std::string& type) {auto it = factoryRegistry.find(type);if (it == factoryRegistry.end()) {throw std::invalid_argument("未知车型: " + type);}return std::unique_ptr<Car>(it->second->create());}
};// 初始化全局映射表(静态成员变量定义)
std::unordered_map<std::string, std::unique_ptr<CarFactory>> GlobalCarFactory::factoryRegistry;// ------------------------- 初始化注册(可在程序启动时完成) -------------------------
void initFactoryRegistry() {// 注册现有工厂GlobalCarFactory::registerFactory("sedan", std::make_unique<SedanFactory>());GlobalCarFactory::registerFactory("suv", std::make_unique<SUVFactory>());// 新增产品时,仅需在此注册新工厂(无需修改GlobalCarFactory类)GlobalCarFactory::registerFactory("truck", std::make_unique<TruckFactory>());
}// ------------------------- 客户端代码 -------------------------
int main() {initFactoryRegistry(); // 程序启动时初始化注册// 客户端仅需传递类型名称,无需知道具体工厂类auto sedan = GlobalCarFactory::createCar("sedan"); // 驾驶轿车auto suv = GlobalCarFactory::createCar("suv"); // 驾驶SUVauto truck = GlobalCarFactory::createCar("truck"); // 驾驶卡车(新增产品)sedan->drive();suv->drive();truck->drive();return 0;
}
通过注册式工厂模式,可以完美融合工厂方法模式的扩展性与简单工厂模式的易用性:
- 客户端仅需传递类型名称,无需关心具体工厂类,使用体验与简单工厂一致。
- 扩展性:新增产品时只需添加新的工厂类并注册,无需修改现有代码,符合开闭原则。