💻CS 设计模式

工厂模式

难度:⭐⭐ | 高频指数:🔥🔥

面试回答

常见问法

  • 简单工厂、工厂方法、抽象工厂有什么区别?
  • 什么时候用工厂模式?
  • 工厂模式解决什么问题?
  • C++ 中工厂模式怎么配合智能指针?
  • 工厂模式和直接 new 有什么区别?

回答

工厂模式的核心思想是将对象的创建和使用分离,调用者不需要知道具体创建了哪个类的对象。

三种工厂模式:

模式特点适用场景
简单工厂一个工厂类,根据参数创建不同产品产品种类少、不常变化
工厂方法每个产品对应一个工厂类产品种类多、需要扩展
抽象工厂创建一组相关产品(产品族)多个产品有关联关系

简单工厂示例:

class Shape {
public:
    virtual void draw() = 0;
    virtual ~Shape() = default;
};

class Circle : public Shape { /* ... */ };
class Rectangle : public Shape { /* ... */ };

// 简单工厂
class ShapeFactory {
public:
    static std::unique_ptr<Shape> create(const std::string& type) {
        if (type == "circle") return std::make_unique<Circle>();
        if (type == "rect")   return std::make_unique<Rectangle>();
        return nullptr;
    }
};

// 使用:调用者不需要知道具体类
auto shape = ShapeFactory::create("circle");
shape->draw();

工厂模式解决的问题:

  1. 解耦创建和使用——调用者不依赖具体类
  2. 集中管理创建逻辑——新增产品只改工厂
  3. 配合多态——返回基类指针,运行时决定具体类型

追问

1. 简单工厂的缺点?

违反开闭原则:每新增一种产品,都要修改工厂类的 if-else。产品种类多时代码臃肿。

2. 工厂方法怎么解决这个问题?

每个产品对应一个工厂类,新增产品只需新增工厂,不修改已有代码。

3. 什么时候用工厂,什么时候直接 new?

  • 创建逻辑简单、类型固定 → 直接 new
  • 需要根据配置/参数决定类型 → 工厂
  • 创建过程复杂(需要初始化、注册等) → 工厂
  • 需要解耦调用者和具体类 → 工厂

原理展开

1. 工厂方法模式

// 产品接口
class Logger {
public:
    virtual void log(const std::string& msg) = 0;
    virtual ~Logger() = default;
};

class FileLogger : public Logger {
public:
    void log(const std::string& msg) override {
        // 写入文件
    }
};

class ConsoleLogger : public Logger {
public:
    void log(const std::string& msg) override {
        // 输出到控制台
    }
};

// 工厂接口
class LoggerFactory {
public:
    virtual std::unique_ptr<Logger> createLogger() = 0;
    virtual ~LoggerFactory() = default;
};

// 具体工厂
class FileLoggerFactory : public LoggerFactory {
public:
    std::unique_ptr<Logger> createLogger() override {
        return std::make_unique<FileLogger>();
    }
};

class ConsoleLoggerFactory : public LoggerFactory {
public:
    std::unique_ptr<Logger> createLogger() override {
        return std::make_unique<ConsoleLogger>();
    }
};

// 使用
void process(LoggerFactory& factory) {
    auto logger = factory.createLogger();
    logger->log("processing...");
}

优点: 符合开闭原则,新增产品只需新增工厂类。 缺点: 类的数量翻倍(每个产品一个工厂)。

2. 抽象工厂模式

抽象工厂创建一组相关产品(产品族),保证产品配套。例如 UI 工厂同时创建按钮和文本框,Windows 工厂创建 Windows 风格的组件,Mac 工厂创建 Mac 风格的组件。

// 抽象工厂接口
class UIFactory {
public:
    virtual std::unique_ptr<Button> createButton() = 0;
    virtual std::unique_ptr<TextBox> createTextBox() = 0;
    virtual ~UIFactory() = default;
};

// 具体工厂保证创建的产品是配套的
class WinFactory : public UIFactory { /* 创建 Win 风格组件 */ };
class MacFactory : public UIFactory { /* 创建 Mac 风格组件 */ };

3. 注册式工厂(实际工程常用)

class ShapeFactory {
public:
    using Creator = std::function<std::unique_ptr<Shape>()>;

    // 注册产品
    static void registerShape(const std::string& name, Creator creator) {
        getRegistry()[name] = std::move(creator);
    }

    // 创建产品
    static std::unique_ptr<Shape> create(const std::string& name) {
        auto it = getRegistry().find(name);
        if (it != getRegistry().end()) {
            return it->second();
        }
        return nullptr;
    }

private:
    static std::unordered_map<std::string, Creator>& getRegistry() {
        static std::unordered_map<std::string, Creator> registry;
        return registry;
    }
};

// 注册(可以在各自的 .cpp 文件中)
static bool _ = [] {
    ShapeFactory::registerShape("circle", [] {
        return std::make_unique<Circle>();
    });
    return true;
}();

优点:

  • 完全符合开闭原则
  • 新增产品不需要修改工厂代码
  • 支持动态注册(插件系统)

4. 配合智能指针的最佳实践

// ✅ 工厂返回 unique_ptr(推荐)
class Factory {
public:
    static std::unique_ptr<Base> create(const std::string& type);
};

// 调用者可以选择所有权模型
auto obj = Factory::create("type");           // 独占
std::shared_ptr<Base> shared = Factory::create("type");  // 转为共享

// ❌ 工厂返回裸指针(不推荐)
// 调用者容易忘记 delete

为什么返回 unique_ptr:

  • 明确所有权转移
  • 调用者可以转为 shared_ptr(反过来不行)
  • 异常安全
  • 零开销(unique_ptr 和裸指针一样大)

5. 工厂模式 vs Builder 模式

对比项工厂模式Builder 模式
关注点创建哪种产品怎么一步步构建产品
产品复杂度简单对象复杂对象(多个部件)
创建过程一步完成分步骤构建
典型场景根据类型创建不同对象构建有很多可选参数的对象

6. 实际工程中的工厂应用


易错点

  • 混淆三种工厂模式——简单工厂是一个类内 if-else,工厂方法是多个工厂类,抽象工厂是创建产品族。
  • 说”工厂模式就是用来替代 new 的”——不是所有 new 都需要工厂,简单场景直接 new 更清晰。
  • 忘记返回智能指针——C++ 中工厂返回裸指针是不好的实践。
  • 过度使用工厂模式——只有一种产品、不需要扩展时,工厂模式是过度设计。
  • 不知道注册式工厂——这是实际工程中最常用的变体。
  • 说不出工厂模式的适用场景——要能举出具体例子(数据库驱动、日志后端等)。

记忆技巧

  • 工厂核心思想:创建和使用分离,调用者不依赖具体类
  • 三种工厂递进:简单(if-else)→ 方法(多工厂类)→ 抽象(产品族)
  • 简单工厂缺点:违反开闭原则(要改 if-else)
  • 返回类型口诀:工厂返回 unique_ptr,调用者决定所有权
  • 什么时候用:类型由运行时决定、创建逻辑复杂、需要解耦

面试速答版

工厂模式将对象的创建和使用分离。简单工厂用一个类根据参数创建不同产品,缺点是违反开闭原则。工厂方法为每个产品定义一个工厂类,新增产品只需新增工厂。抽象工厂创建一组相关产品(产品族),保证产品配套。C++ 中工厂应返回 unique_ptr,明确所有权转移且异常安全。实际工程常用注册式工厂(map + function),支持动态注册新产品。适用场景:类型由运行时决定、创建逻辑复杂、需要解耦调用者和具体类。

Related · 设计模式