应使用工厂而非new直接创建对象,因new硬编码导致调用方与具体类强耦合,更换实现需修改多处;工厂将构造逻辑集中,上层仅依赖接口,增删子类不影响业务代码。

为什么不用 new 直接创建对象而要用工厂
因为硬编码 new Derived() 会让调用方和具体类强耦合,一旦要换实现(比如从 MySQLLogger 切到 FileLogger),就得改所有 new 地方。工厂把“怎么造”收拢到一处,上层只依赖接口或基类指针,后续增删子类不波及业务代码。
简单工厂:一个函数返回不同子类指针
它不是 GoF 23 种设计模式之一,但最易理解,适合产品种类少、不常扩展的场景。核心是用参数控制构造逻辑,返回统一基类指针。
常见错误:返回栈对象地址、忘记虚析构、参数类型不安全(比如用 int 枚举易错且难维护)。
- 基类必须有
virtual ~Base() = default;,否则通过基类指针 delete 派生对象会未定义行为 - 推荐用
std::string或枚举类(enum class)作参数,比裸int更可读、类型安全 - 工厂函数内部用
if-else或switch分支,别用宏或全局变量拼类型名
class Product { public: virtual ~Product() = default; virtual void operation() = 0; };
class ConcreteA : public Product { public: void operation() override { std::cout << "A\n"; } };
class ConcreteB : public Product { public: void operation() override { std::cout << "B\n"; } };
enum class ProductType { A, B };
std::unique_ptr createProduct(ProductType type) {
switch (type) {
case ProductType::A: return std::make_unique();
case ProductType::B: return std::make_unique();
default: throw std::invalid_argument("unknown product type");
}
}
抽象工厂:解决“一族产品”的创建问题
当系统需要创建多个相关或相互依赖的对象(比如 Windows 风格控件 + 渲染器,macOS 风格控件 + 渲染器),就不能靠一个简单工厂了。抽象工厂定义接口,由具体工厂实现——每个具体工厂负责一整套配套子类的创建。
立即学习“C++免费学习笔记(深入)”;
容易踩的坑:误把抽象工厂当成“多个简单工厂的集合”,其实关键在“族”的约束;另外,C++ 中抽象工厂接口通常返回 std::unique_ptr 或原始指针,但必须确保调用方清楚所有权归属。
- 抽象工厂类本身是纯接口(全
virtual函数),不包含状态 - 每个具体工厂(如
WinFactory、MacFactory)继承它,并实现所有创建函数 - 产品之间要有逻辑关联性,比如
Button和Checkbox必须来自同一个工厂,否则 UI 风格不一致
class Button { public: virtual ~Button() = default; virtual void paint() = 0; };
class Checkbox { public: virtual ~Checkbox() = default; virtual void render() = 0; };
class GUIFactory {
public:
virtual std::unique_ptr
什么时候该选哪种工厂
简单工厂够用就别上抽象工厂——后者增加至少 3 倍类数量(抽象工厂接口、N 个具体工厂、M 个产品族)。但若已有多个产品需协同工作,或者未来明确要支持多平台/多后端,抽象工厂的扩展成本反而更低。
真正麻烦的是“半抽象”场景:比如产品种类固定,但每种产品又有多个变体(如 EncryptedLogger / PlainLogger)。这时往往得组合策略模式或模板工厂,而不是硬塞进抽象工厂层级里。









