【设计模式】C++ 工厂模式的理解
工厂模式是一种创建型设计模式,它提供了一种创建对象的接口,但允许子类决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。
核心思想
将对象的创建与使用分离,客户端不需要知道具体创建哪个类的实例,只需要通过工厂接口获取所需对象。
主要类型
1. 简单工厂模式(Simple Factory)
-
一个工厂类根据传入的参数创建不同的对象
-
不符合开闭原则(新增产品需要修改工厂类)
// 产品接口
interface Product {
void operation();
}
// 具体产品
class ConcreteProductA implements Product {
public void operation() {
System.out.println("Product A");
}
}
class ConcreteProductB implements Product {
public void operation() {
System.out.println("Product B");
}
}
// 简单工厂
class SimpleFactory {
public static Product createProduct(String type) {
if ("A".equals(type)) {
return new ConcreteProductA();
} else if ("B".equals(type)) {
return new ConcreteProductB();
}
return null;
}
}
2. 工厂方法模式(Factory Method)
-
定义一个创建对象的接口,让子类决定实例化哪个类
-
符合开闭原则
// 工厂接口
interface Factory {
Product createProduct();
}
// 具体工厂
class FactoryA implements Factory {
public Product createProduct() {
return new ConcreteProductA();
}
}
class FactoryB implements Factory {
public Product createProduct() {
return new ConcreteProductB();
}
}
3. 抽象工厂模式(Abstract Factory)
-
创建相关或依赖对象的家族,而不需要指定具体类
-
适合创建一系列相关产品
// 抽象工厂
interface AbstractFactory {
Product createProduct();
AnotherProduct createAnotherProduct();
}
// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {
public Product createProduct() {
return new ProductA();
}
public AnotherProduct createAnotherProduct() {
return new AnotherProductA();
}
}
优点
-
解耦:客户端与具体产品类分离
-
可扩展:新增产品类型时无需修改现有代码(工厂方法模式)
-
单一职责:将创建逻辑集中管理
-
易于维护:对象创建代码集中管理
缺点
-
增加复杂度:需要引入多个类和接口
-
理解成本:对新手可能较难理解
应用场景
-
当一个类不知道它所需要的对象类时
-
当一个类希望由其子类来指定创建的对象时
-
当需要将对象的创建与使用分离时
-
系统需要支持多种产品类型时
现实例子
// JDK 中的 Calendar.getInstance()
Calendar cal = Calendar.getInstance();
// 根据本地化设置返回不同的 Calendar 子类实例
// Spring 中的 BeanFactory
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
Object bean = context.getBean("beanName");
工厂模式是面向对象设计中非常重要的模式,它体现了"针对接口编程,而不是针对实现编程"的原则。
我来用一个汽车制造工厂的例子,用 C++ 实现工厂模式。这个例子非常直观易懂!
场景描述
假设我们有一个汽车工厂,能生产不同类型的汽车(轿车、SUV、卡车)。
1. 简单工厂模式示例
#include <iostream>
#include <string>
using namespace std;
// 1. 抽象产品类 - 汽车
class Car {
public:
virtual void drive() = 0;
virtual ~Car() {}
};
// 2. 具体产品类
class Sedan : public Car {
public:
void drive() override {
cout << "驾驶轿车:平稳舒适" << endl;
}
};
class SUV : public Car {
public:
void drive() override {
cout << "驾驶SUV:越野能力强" << endl;
}
};
class Truck : public Car {
public:
void drive() override {
cout << "驾驶卡车:载货量大" << endl;
}
};
// 3. 简单工厂
class CarFactory {
public:
static Car* createCar(const string& type) {
if (type == "sedan") {
return new Sedan();
} else if (type == "suv") {
return new SUV();
} else if (type == "truck") {
return new Truck();
}
return nullptr;
}
};
// 4. 客户端使用
int main() {
// 客户只需要告诉工厂要什么类型的车,不需要知道具体怎么创建
Car* myCar1 = CarFactory::createCar("sedan");
Car* myCar2 = CarFactory::createCar("suv");
Car* myCar3 = CarFactory::createCar("truck");
if (myCar1) myCar1->drive(); // 驾驶轿车:平稳舒适
if (myCar2) myCar2->drive(); // 驾驶SUV:越野能力强
if (myCar3) myCar3->drive(); // 驾驶卡车:载货量大
// 清理内存
delete myCar1;
delete myCar2;
delete myCar3;
return 0;
}
2. 工厂方法模式示例(更灵活)
#include <iostream>
#include <memory>
using namespace std;
// 抽象产品
class Car {
public:
virtual void drive() = 0;
virtual ~Car() {}
};
// 具体产品
class Benz : public Car {
public:
void drive() override {
cout << "驾驶奔驰:豪华舒适" << endl;
}
};
class BMW : public Car {
public:
void drive() override {
cout << "驾驶宝马:运动操控" << endl;
}
};
// 抽象工厂
class CarFactory {
public:
virtual unique_ptr<Car> produceCar() = 0;
virtual ~CarFactory() {}
};
// 具体工厂
class BenzFactory : public CarFactory {
public:
unique_ptr<Car> produceCar() override {
return make_unique<Benz>();
}
};
class BMWFactory : public CarFactory {
public:
unique_ptr<Car> produceCar() override {
return make_unique<BMW>();
}
};
// 客户端
int main() {
// 创建奔驰工厂
unique_ptr<CarFactory> benzFactory = make_unique<BenzFactory>();
unique_ptr<Car> benz = benzFactory->produceCar();
benz->drive(); // 驾驶奔驰:豪华舒适
// 创建宝马工厂
unique_ptr<CarFactory> bmwFactory = make_unique<BMWFactory>();
unique_ptr<Car> bmw = bmwFactory->produceCar();
bmw->drive(); // 驾驶宝马:运动操控
return 0;
}
3. 更实际的例子:图形绘制
#include <iostream>
#include <vector>
using namespace std;
// 图形基类
class Shape {
public:
virtual void draw() = 0;
virtual ~Shape() {}
};
// 具体图形
class Circle : public Shape {
public:
void draw() override {
cout << "绘制圆形 ○" << endl;
}
};
class Rectangle : public Shape {
public:
void draw() override {
cout << "绘制矩形 ▭" << endl;
}
};
class Triangle : public Shape {
public:
void draw() override {
cout << "绘制三角形 △" << endl;
}
};
// 图形工厂
class ShapeFactory {
public:
static Shape* createShape(const string& type) {
if (type == "circle") {
return new Circle();
} else if (type == "rectangle") {
return new Rectangle();
} else if (type == "triangle") {
return new Triangle();
}
return nullptr;
}
};
int main() {
// 用户输入想要创建的图形
vector<string> requests = {"circle", "rectangle", "triangle"};
cout << "开始绘制图形:" << endl;
for (const auto& request : requests) {
Shape* shape = ShapeFactory::createShape(request);
if (shape) {
shape->draw();
delete shape; // 记得释放内存
}
}
return 0;
}
关键理解点
为什么用工厂模式?
假设没有工厂模式:
// 客户端需要知道所有具体类
Car* car;
if (userChoice == "sedan") {
car = new Sedan();
} else if (userChoice == "suv") {
car = new SUV();
} else if (userChoice == "truck") {
car = new Truck();
}
// 每次新增车型都要修改这里
有了工厂模式:
// 客户端代码很简单,与具体类解耦
Car* car = CarFactory::createCar(userChoice);
// 新增车型只需要修改工厂类,客户端代码不变
输出结果
开始绘制图形:
绘制圆形 ○
绘制矩形 ▭
绘制三角形 △
总结
工厂模式就像现实生活中的餐馆:
-
顾客(客户端):只需要点菜("我要一个披萨")
-
服务员(工厂):接收订单,告诉厨房做什么
-
厨房(具体工厂):根据订单制作具体的披萨(芝士披萨、海鲜披萨等)
-
顾客最终得到披萨,但不需要知道披萨的具体制作过程
这种模式让代码更灵活、可维护、易扩展!
你的理解基本正确,但让我先回答第一个问题,然后补充一下你的理解。
1. 为什么用 static Car* 而不用智能指针?
你观察得很仔细!用原始指针确实不是最佳实践。现代C++应该使用智能指针。让我展示更好的实现:
#include <iostream>
#include <memory>
using namespace std;
// 产品类
class Car {
public:
virtual void drive() = 0;
virtual ~Car() = default;
};
class Sedan : public Car {
public:
void drive() override {
cout << "驾驶轿车" << endl;
}
};
// 使用智能指针的工厂
class CarFactory {
public:
static unique_ptr<Car> createCar(const string& type) {
if (type == "sedan") {
return make_unique<Sedan>();
} else if (type == "suv") {
return make_unique<SUV>(); // 假设有SUV类
}
return nullptr;
}
};
// 客户端使用
int main() {
// 使用智能指针,无需手动delete
auto myCar = CarFactory::createCar("sedan");
if (myCar) {
myCar->drive();
}
// myCar会自动释放内存
return 0;
}
为什么很多教程用原始指针?
-
历史原因:老教程或教材
-
简洁性:为了专注于模式本身
-
跨语言兼容:让Java/C#程序员容易理解
2. 你对工厂模式的理解(补充说明)
你的理解方向是对的,但让我更精确地描述一下:
// 你的理解:"对于一个需求有好几种实现方式"
// 确实如此!比如"驾驶汽车"这个需求
// 1. 首先定义抽象接口(需求规范)
class Car {
public:
virtual void drive() = 0; // 驾驶需求
virtual void fuel() = 0; // 加油需求
virtual ~Car() {}
};
// 2. "每种方式都是一个类"(多种实现)
class ElectricCar : public Car { // 方式1:电动汽车
public:
void drive() override { cout << "电力驱动" << endl; }
void fuel() override { cout << "充电" << endl; }
};
class GasolineCar : public Car { // 方式2:汽油车
public:
void drive() override { cout << "汽油驱动" << endl; }
void fuel() override { cout << "加油" << endl; }
};
class HybridCar : public Car { // 方式3:混合动力
public:
void drive() override { cout << "混合驱动" << endl; }
void fuel() override { cout << "加油或充电" << endl; }
};
// 3. "工厂把这些类抽象成一个类,供上层调用"
class CarFactory {
public:
// 工厂方法:根据参数创建具体对象
static unique_ptr<Car> createCar(const string& type) {
if (type == "electric") {
return make_unique<ElectricCar>();
} else if (type == "gasoline") {
return make_unique<GasolineCar>();
} else if (type == "hybrid") {
return make_unique<HybridCar>();
}
return nullptr;
}
};
// 4. "最上层调用"(客户端代码)
class Client {
public:
void useCar() {
// 客户端只需要知道抽象类型Car,不知道具体实现
unique_ptr<Car> myCar = CarFactory::createCar("electric");
// 统一接口调用
myCar->drive(); // 可能是电力驱动
myCar->fuel(); // 可能是充电
// 换个类型试试
myCar = CarFactory::createCar("gasoline");
myCar->drive(); // 现在是汽油驱动
myCar->fuel(); // 现在是加油
}
};
3. 更生动的现实比喻
想象一个外卖平台:
// 抽象:食物
class Food {
public:
virtual void prepare() = 0;
virtual void deliver() = 0;
};
// 具体食物
class Pizza : public Food {
void prepare() override { cout << "制作披萨" << endl; }
void deliver() override { cout << "配送披萨" << endl; }
};
class Burger : public Food {
void prepare() override { cout << "制作汉堡" << endl; }
void deliver() override { cout << "配送汉堡" << endl; }
};
// 用户(客户端)
class Customer {
public:
void orderFood(const string& foodType) {
// 用户只调用FoodFactory,不知道具体餐厅
unique_ptr<Food> food = FoodFactory::order(foodType);
food->prepare();
food->deliver();
}
};
// 外卖平台(工厂)
class FoodFactory {
public:
static unique_ptr<Food> order(const string& type) {
if (type == "pizza") {
return make_unique<Pizza>(); // 可能调用披萨店
} else if (type == "burger") {
return make_unique<Burger>(); // 可能调用汉堡店
}
return nullptr;
}
};
4. 关键优势总结
工厂模式的核心价值:
// 没有工厂模式:客户端需要知道所有具体类
void badExample() {
string choice = getUserChoice();
if (choice == "electric") {
ElectricCar car;
car.drive();
} else if (choice == "gasoline") {
GasolineCar car;
car.drive();
} else if (choice == "hybrid") {
HybridCar car;
car.drive();
}
// 新增类型时,需要修改这里!
}
// 使用工厂模式:客户端只依赖抽象
void goodExample() {
string choice = getUserChoice();
// 创建逻辑封装在工厂中
unique_ptr<Car> car = CarFactory::createCar(choice);
car->drive(); // 多态调用
// 新增类型时,只需修改工厂,这里不变!
}
总结
你的理解正确,工厂模式就是:
-
抽象共性:多个具体类实现同一个接口
-
封装创建:把对象创建的复杂度隐藏起来
-
解耦调用:客户端只依赖抽象,不依赖具体类
简单说:工厂就像是一个"黑盒子",你告诉它你要什么(参数),它就给你相应的对象。你不需要知道对象是怎么被创建出来的,也不需要知道具体的实现类是谁。
这种设计让代码:
-
✅ 更易维护:创建逻辑集中管理
-
✅ 更易扩展:新增类型不影响现有代码
-
✅ 更灵活:可以动态切换实现
-
✅ 更安全:使用智能指针避免内存泄漏
这是一个很好的问题!很多人刚开始学工厂模式时都有这个疑问。让我用一个具体的例子来解释为什么需要工厂类。
直接使用抽象类的问题
// 假设有这些类
class Animal {
public:
virtual void speak() = 0;
};
class Dog : public Animal {
public:
void speak() override { cout << "汪汪!" << endl; }
};
class Cat : public Animal {
public:
void speak() override { cout << "喵喵!" << endl; }
};
// 客户端代码
int main() {
// 错误!不能直接实例化抽象类
// Animal animal; // 编译错误
// 必须知道具体类
Animal* pet1 = new Dog(); // 客户端依赖Dog类
Animal* pet2 = new Cat(); // 客户端依赖Cat类
pet1->speak();
pet2->speak();
delete pet1;
delete pet2;
return 0;
}
问题所在
1. 客户端代码与具体类耦合
// 问题:客户端需要知道所有具体类
void createPet(const string& type) {
Animal* pet = nullptr;
if (type == "dog") {
pet = new Dog(); // 直接依赖Dog类
} else if (type == "cat") {
pet = new Cat(); // 直接依赖Cat类
} else if (type == "bird") {
pet = new Bird(); // 新增类型时,要修改这里!
}
// 使用pet...
}
每新增一个动物类型,都要修改客户端代码!
2. 对象创建逻辑分散
// 多个地方都需要创建动物
class PetShop {
Animal* buyPet(const string& type) {
if (type == "dog") return new Dog();
if (type == "cat") return new Cat();
return nullptr;
}
};
class Zoo {
Animal* getAnimal(const string& type) {
if (type == "dog") return new Dog();
if (type == "cat") return new Cat(); // 重复的创建逻辑!
return nullptr;
}
};
// 创建逻辑重复了!修改时要在多个地方改
解决方案:使用工厂类
// 动物工厂
class AnimalFactory {
public:
static unique_ptr<Animal> createAnimal(const string& type) {
if (type == "dog") {
return make_unique<Dog>();
} else if (type == "cat") {
return make_unique<Cat>();
} else if (type == "bird") {
return make_unique<Bird>();
}
return nullptr;
}
};
// 客户端代码
int main() {
// 客户端只依赖抽象类和工厂,不依赖具体类
vector<string> petTypes = {"dog", "cat", "bird"};
for (const auto& type : petTypes) {
auto pet = AnimalFactory::createAnimal(type);
pet->speak(); // 多态调用
}
return 0;
}
工厂类的核心价值
1. 封装变化点
// 假设创建逻辑很复杂
class AnimalFactory {
public:
static unique_ptr<Animal> createAnimal(const string& type) {
// 复杂的创建逻辑都封装在这里
if (type == "dog") {
// 可能需要:读取配置、初始化数据、注册到管理器等
auto dog = make_unique<Dog>();
dog->setAge(calculateDogAge());
dog->registerToKennel();
return dog;
}
else if (type == "cat") {
// 猫的创建逻辑可能完全不同
auto cat = make_unique<Cat>();
cat->setColor(readConfig("cat_color"));
cat->vaccinate();
return cat;
}
// ... 其他复杂逻辑
}
};
// 客户端完全不知道这些复杂性
auto pet = AnimalFactory::createAnimal("dog");
// 客户端拿到的是完全初始化好的对象
2. 统一管理创建逻辑
// 没有工厂:每个使用的地方都要写创建逻辑
void function1() {
if (condition) {
Animal* a = new Dog();
} else {
Animal* a = new Cat();
}
}
void function2() {
if (condition) {
Animal* a = new Dog(); // 重复代码!
} else {
Animal* a = new Cat();
}
}
// 有工厂:创建逻辑统一管理
void function1() {
auto animal = AnimalFactory::createAnimal(getType());
}
void function2() {
auto animal = AnimalFactory::createAnimal(getType());
}
3. 便于扩展和维护
// 初始版本
class AnimalFactory {
public:
static Animal* createAnimal(const string& type) {
if (type == "dog") return new Dog();
if (type == "cat") return new Cat();
return nullptr;
}
};
// 版本2:添加缓存
class AnimalFactory {
private:
static unordered_map<string, Animal*> cache;
public:
static Animal* createAnimal(const string& type) {
// 检查缓存
if (cache.find(type) != cache.end()) {
return cache[type]->clone(); // 原型模式
}
// 创建新对象
Animal* animal = nullptr;
if (type == "dog") animal = new Dog();
else if (type == "cat") animal = new Cat();
// 加入缓存
if (animal) cache[type] = animal;
return animal ? animal->clone() : nullptr;
}
};
// 版本3:从配置文件读取
class AnimalFactory {
public:
static Animal* createAnimal(const string& type) {
// 从XML/JSON配置文件读取创建参数
Config config = loadConfig("animals.xml");
string className = config.getClassName(type);
// 使用反射动态创建
return Reflection::createInstance(className);
}
};
// 客户端代码完全不需要修改!
// auto pet = AnimalFactory::createAnimal("dog");
一个更实际的例子
// 数据库连接示例
class DatabaseConnection {
public:
virtual void connect() = 0;
virtual void query(const string& sql) = 0;
};
class MySQLConnection : public DatabaseConnection {
public:
void connect() override { cout << "连接MySQL" << endl; }
void query(const string& sql) override { cout << "执行MySQL查询: " << sql << endl; }
};
class PostgreSQLConnection : public DatabaseConnection {
public:
void connect() override { cout << "连接PostgreSQL" << endl; }
void query(const string& sql) override { cout << "执行PostgreSQL查询: " << sql << endl; }
};
// 为什么需要工厂?
class DatabaseFactory {
public:
static unique_ptr<DatabaseConnection> createConnection(const string& dbType) {
// 这里可能有复杂的逻辑:
// 1. 读取配置文件
// 2. 设置连接参数
// 3. 初始化连接池
// 4. 验证权限
// 5. 记录日志等
if (dbType == "mysql") {
auto conn = make_unique<MySQLConnection>();
// 初始化MySQL特定参数
conn->setCharset("utf8mb4");
conn->setTimeout(30);
return conn;
} else if (dbType == "postgresql") {
auto conn = make_unique<PostgreSQLConnection>();
// 初始化PostgreSQL特定参数
conn->setSchema("public");
return conn;
}
return nullptr;
}
};
// 客户端使用
class Application {
public:
void run() {
// 简单的一行代码,背后是复杂的创建逻辑
auto db = DatabaseFactory::createConnection("mysql");
db->connect();
db->query("SELECT * FROM users");
}
};
总结
为什么需要工厂类:
-
解耦:客户端不依赖具体类,只依赖抽象
-
封装:把复杂的创建逻辑封装起来
-
集中管理:创建逻辑在同一个地方,便于维护
-
可扩展:新增类型时,只需修改工厂,不影响客户端
-
可配置:可以通过配置文件等动态决定创建什么对象
简单比喻:
-
没有工厂:你要吃披萨,得自己去买面粉、奶酪、烤箱,自己烤
-
有工厂:你打电话给披萨店说"我要一个披萨",店里准备好一切送给你
工厂类就是那个"披萨店",帮你处理所有复杂的创建过程!
你的理解非常准确! 工厂模式本质上就是 "增强版"的抽象类用法。让我用你的这个思路来重新解释。
工厂 = 抽象类用法的增强
1. 基础抽象类用法(不够强)
// 1. 定义抽象接口
class Animal {
public:
virtual void speak() = 0;
virtual ~Animal() {}
};
// 2. 具体实现
class Dog : public Animal {
public:
void speak() override { cout << "汪汪" << endl; }
};
class Cat : public Animal {
public:
void speak() override { cout << "喵喵" << endl; }
};
// 3. 客户端直接使用(问题所在)
void clientCode() {
// 客户端需要知道具体类名
Animal* pet = new Dog(); // 直接依赖Dog类
// 如果要换类型,必须修改代码
// Animal* pet = new Cat(); // 需要手动改
pet->speak();
delete pet;
}
问题:抽象类解决了"怎么用",但没解决"怎么创建"。
2. 增强版:工厂模式
// 增强点1:封装创建逻辑
class AnimalCreator {
public:
// 动态决定创建哪个具体类
static Animal* createAnimal(const string& type) {
if (type == "dog") return new Dog();
if (type == "cat") return new Cat();
return nullptr;
}
};
// 客户端使用增强版
void enhancedClientCode() {
// 运行时决定创建什么
string userChoice = "dog"; // 可以从配置文件、用户输入等获取
// 不依赖具体类名!
Animal* pet = AnimalCreator::createAnimal(userChoice);
pet->speak();
// 想换类型?只需改配置/输入,代码不变
userChoice = "cat";
Animal* anotherPet = AnimalCreator::createAnimal(userChoice);
anotherPet->speak();
}
工厂模式增强了什么?
增强1:创建过程的抽象化
// 没有工厂:创建与使用混合
void process1() {
Animal* a = new Dog(); // 创建
a->speak(); // 使用
delete a;
}
void process2() {
Animal* a = new Dog(); // 重复创建逻辑
a->run();
delete a;
}
// 有工厂:创建逻辑抽象化
void process1() {
Animal* a = AnimalFactory::create("dog"); // 抽象化创建
a->speak();
delete a;
}
void process2() {
Animal* a = AnimalFactory::create("dog"); // 复用创建逻辑
a->run();
delete a;
}
增强2:条件创建的封装
// 复杂的选择逻辑被封装
class SmartAnimalFactory {
public:
static Animal* createOptimalAnimal() {
// 这个逻辑可能很复杂,但客户端不需要知道
// 根据系统资源决定
if (hasLowMemory()) {
return new SmallDog(); // 内存占用小的狗
}
// 根据用户偏好决定
if (userLikesCats()) {
return new PersianCat(); // 波斯猫
}
// 根据时间决定
if (isNightTime()) {
return new Owl(); // 夜行动物
}
// 默认
return new GenericDog();
}
};
// 客户端很简单
auto pet = SmartAnimalFactory::createOptimalAnimal();
// 不知道背后复杂的决策逻辑
增强3:创建过程的扩展点
// 可以添加各种"钩子"和扩展
class ConfigurableFactory {
public:
static Animal* createWithConfig(const string& type) {
// 1. 记录日志
log("开始创建动物: " + type);
// 2. 验证权限
if (!hasPermission(type)) {
throw PermissionException();
}
// 3. 创建对象
Animal* animal = nullptr;
if (type == "dog") animal = new Dog();
else if (type == "cat") animal = new Cat();
// 4. 后处理
if (animal) {
animal->initializeFromConfig();
registerToTracker(animal);
}
// 5. 更多处理...
return animal;
}
};
用你的话来理解
抽象类本身:
// 抽象类解决了"接口统一"问题
// 告诉客户端:"所有动物都有speak()方法"
class Animal {
virtual void speak() = 0; // 接口规范
};
// 客户端知道怎么用
animal->speak(); // 多态调用
工厂增强:
// 工厂解决了"实例化统一"问题
// 告诉客户端:"所有动物都通过我来创建"
class AnimalFactory {
static Animal* create(string type); // 创建规范
};
// 客户端知道怎么创建
Animal* animal = AnimalFactory::create("dog");
// 不用关心是new Dog()还是new Cat()
一个完整对比
// ================ 方案1:只用抽象类 ================
// 问题:创建逻辑分散在各处
class Game {
Character* createHero() {
// 需要知道所有具体类
if (weapon == "sword") return new Warrior();
if (weapon == "bow") return new Archer();
if (weapon == "staff") return new Mage();
return nullptr;
}
Character* createEnemy() {
// 重复的创建逻辑
if (type == "orc") return new Orc();
if (type == "goblin") return new Goblin();
return nullptr;
}
};
// ================ 方案2:抽象类+工厂(增强版) ================
class CharacterFactory {
static Character* create(string type) {
// 集中管理所有创建逻辑
if (type == "warrior" || type == "sword") return new Warrior();
if (type == "archer" || type == "bow") return new Archer();
if (type == "mage" || type == "staff") return new Mage();
if (type == "orc") return new Orc();
if (type == "goblin") return new Goblin();
return nullptr;
}
};
class Game {
Character* createHero() {
// 统一接口创建
return CharacterFactory::create(weapon);
}
Character* createEnemy() {
return CharacterFactory::create(enemyType);
}
};
总结
你的理解完全正确:
-
抽象类解决了"如何统一使用"的问题(接口抽象)
-
工厂模式解决了"如何统一创建"的问题(创建抽象)
工厂模式 = 抽象类用法 + 创建逻辑的封装
就像:
-
抽象类:定义了汽车的驾驶接口(
drive()) -
工厂模式:定义了如何获得一辆汽车(
createCar())
两者结合,才实现了完整的"面向接口编程"理念:既不依赖具体实现类来使用对象,也不依赖具体实现类来创建对象。
你说到了工厂模式的一个关键痛点!确实,如果只是把 new Dog() 换成 createAnimal("dog"),感觉只是换了一种依赖而已。让我深入解释为什么这实际上是一个重要改进。
问题:还是要记字符串啊!
// 看起来只是换了个依赖
Animal* pet1 = new Dog(); // 要记类名Dog
Animal* pet2 = create("dog"); // 要记字符串"dog"
// 好像没太大区别?
关键改进:字符串比类名灵活得多!
1. 运行时决定 vs 编译时决定
// 方案A:直接new(编译时绑定)
void createPet() {
string userInput = getUserInput(); // 用户输入"cat"
if (userInput == "dog") {
Animal* pet = new Dog(); // 编译时就知道是Dog
} else if (userInput == "cat") {
Animal* pet = new Cat(); // 编译时就知道是Cat
}
// 每新增一种动物都要改代码并重新编译!
}
// 方案B:工厂模式(运行时绑定)
class AnimalFactory {
public:
static Animal* create(const string& type) {
if (type == "dog") return new Dog();
if (type == "cat") return new Cat();
return nullptr;
}
};
void createPet() {
string userInput = getUserInput(); // 用户输入"cat"
// 运行时动态创建,代码不需要重新编译!
Animal* pet = AnimalFactory::create(userInput);
}
2. 配置化:完全不需要记字符串!
// 从配置文件读取,根本不需要记字符串
#include <fstream>
#include <json/json.h>
class ConfigDrivenFactory {
public:
static Animal* createFromConfig() {
// 读取配置文件
ifstream configFile("animals.json");
Json::Value config;
configFile >> config;
// 从配置获取类型
string animalType = config["default_animal"].asString();
// 可能是"dog"、"cat"、"bird",但程序员不需要知道!
return create(animalType);
}
private:
static Animal* create(const string& type) {
// 工厂内部的映射
static unordered_map<string, function<Animal*()>> creators = {
{"dog", []() { return new Dog(); }},
{"cat", []() { return new Cat(); }},
{"bird", []() { return new Bird(); }}
};
if (creators.find(type) != creators.end()) {
return creators[type]();
}
return nullptr;
}
};
// 客户端使用
int main() {
// 完全不知道具体的字符串是什么!
Animal* pet = ConfigDrivenFactory::createFromConfig();
pet->speak(); // 可能是狗叫、猫叫或鸟叫
return 0;
}
3. 枚举或常量:更好的解决方案
// 定义枚举,不用记字符串
enum AnimalType {
DOG,
CAT,
BIRD
};
class AnimalFactory {
public:
static Animal* create(AnimalType type) {
switch (type) {
case DOG: return new Dog();
case CAT: return new Cat();
case BIRD: return new Bird();
default: return nullptr;
}
}
};
// 或者用常量
namespace Animals {
constexpr auto DOG = "dog";
constexpr auto CAT = "cat";
constexpr auto BIRD = "bird";
}
// 客户端使用
int main() {
// 使用枚举,类型安全
Animal* pet1 = AnimalFactory::create(DOG);
// 使用常量,避免拼写错误
Animal* pet2 = AnimalFactory::create(Animals::CAT);
return 0;
}
真正的好处:创建逻辑的复杂性
工厂模式的核心价值在于处理复杂的创建逻辑,而不仅仅是替换 new。
案例1:带缓存的工厂
class AnimalFactory {
private:
static unordered_map<string, shared_ptr<Animal>> prototypeCache;
static void initCache() {
// 预创建原型对象
prototypeCache["dog"] = make_shared<Dog>();
prototypeCache["cat"] = make_shared<Cat>();
prototypeCache["bird"] = make_shared<Bird>();
}
public:
static shared_ptr<Animal> create(const string& type) {
// 延迟初始化缓存
if (prototypeCache.empty()) {
initCache();
}
// 使用原型模式克隆,避免重复初始化开销
if (prototypeCache.find(type) != prototypeCache.end()) {
return prototypeCache[type]->clone();
}
return nullptr;
}
};
案例2:依赖注入的工厂
class AnimalFactory {
private:
// 通过依赖注入配置创建器
unordered_map<string, function<unique_ptr<Animal>()>> creators;
public:
// 注册创建函数,而不是硬编码
void registerCreator(const string& type,
function<unique_ptr<Animal>()> creator) {
creators[type] = creator;
}
unique_ptr<Animal> create(const string& type) {
if (creators.find(type) != creators.end()) {
return creators[type]();
}
return nullptr;
}
};
// 使用
int main() {
AnimalFactory factory;
// 动态注册,不需要修改工厂代码
factory.registerCreator("dog", []() {
auto dog = make_unique<Dog>();
dog->setAge(2);
dog->train();
return dog;
});
factory.registerCreator("cat", []() {
auto cat = make_unique<Cat>();
cat->setColor("orange");
return cat;
});
// 客户端使用
auto pet = factory.create("dog");
return 0;
}
案例3:条件创建的工厂
class SmartAnimalFactory {
public:
static unique_ptr<Animal> create() {
// 基于多种条件自动选择类型
// 客户端完全不知道选择逻辑
if (isApartmentBuilding()) {
// 公寓适合养猫
return make_unique<Cat>();
}
else if (hasLargeYard()) {
// 有大院子适合养狗
return make_unique<Dog>();
}
else if (isQuietNeighborhood()) {
// 安静社区可以养鸟
return make_unique<Bird>();
}
return nullptr;
}
private:
static bool isApartmentBuilding() { /* 检查逻辑 */ }
static bool hasLargeYard() { /* 检查逻辑 */ }
static bool isQuietNeighborhood() { /* 检查逻辑 */ }
};
// 客户端:一句话搞定,什么参数都不用
auto perfectPet = SmartAnimalFactory::create();
最实际的例子:插件系统
// 插件接口
class Plugin {
public:
virtual void execute() = 0;
virtual ~Plugin() {}
};
// 插件工厂
class PluginFactory {
private:
static unordered_map<string, function<unique_ptr<Plugin>()>> pluginRegistry;
public:
// 插件动态注册自己
static void registerPlugin(const string& name,
function<unique_ptr<Plugin>()> creator) {
pluginRegistry[name] = creator;
}
// 根据配置文件加载插件
static vector<unique_ptr<Plugin>> loadPlugins() {
vector<unique_ptr<Plugin>> plugins;
// 读取插件配置
vector<string> pluginNames = readConfigFile("plugins.config");
for (const auto& name : pluginNames) {
if (pluginRegistry.find(name) != pluginRegistry.end()) {
plugins.push_back(pluginRegistry[name]());
}
}
return plugins;
}
};
// 插件实现(在另一个DLL中)
class ImageProcessorPlugin : public Plugin {
public:
void execute() override { cout << "处理图片" << endl; }
// 自动注册
class AutoRegister {
public:
AutoRegister() {
PluginFactory::registerPlugin("image_processor",
[]() { return make_unique<ImageProcessorPlugin>(); });
}
};
};
// 自动注册实例
static ImageProcessorPlugin::AutoRegister imageProcessorReg;
// 主程序
int main() {
// 主程序完全不知道有哪些插件!
auto plugins = PluginFactory::loadPlugins();
for (auto& plugin : plugins) {
plugin->execute(); // 可能是图片处理、数据备份、网络监控...
}
return 0;
}
总结
你的观察很敏锐!如果只是简单替换 new Dog() 为 create("dog"),确实改善有限。但工厂模式的真正威力在于:
-
配置化:可以从文件读取,根本不需要记字符串
-
复杂逻辑封装:创建过程可能涉及缓存、初始化、验证等
-
运行时灵活性:可以动态添加新的创建逻辑
-
依赖管理:可以集中管理对象的依赖关系
-
插件化架构:支持动态扩展
所以工厂模式不是简单的"不用记类名",而是"将创建逻辑抽象化、配置化、复杂化"的能力。
就像去餐厅:
-
记类名 = 要知道每个厨师的电话号码
-
简单工厂 = 记住餐厅电话
-
真正的工厂 = 用手机App点餐,App会根据你的位置、评分、价格等推荐餐厅,你甚至不需要知道餐厅名字!

浙公网安备 33010602011771号