工厂方法(Factory Methods)

定义

工厂方法是一种常用的设计模式,它属于创建型模式,旨在提供一种将对象的实例化过程推迟到子类的方法。工厂方法模式通过定义一个创建对象的接口,但是将具体的实例化延迟到子类中来完成。


工厂方法模式基本结构示例

产品接口(Product)

定义了工厂方法所创建的对象的接口。

class Product {
public:
    virtual void operation() = 0;
    virtual ~Product() {}
};


具体产品(Concrete Product)

实现产品接口,是工厂方法模式所创建的具体对象。

class ConcreteProductA : public Product {
public:
    virtual void operation() override {
        // 具体产品 A 的操作
        std::cout <<"具体产品 A 的操作\n";
    }
};

class ConcreteProductB : public Product {
public:
    virtual void operation() override {
        // 具体产品 B 的操作
        std::cout << "具体产品 B 的操作\n";
    }
};


工厂接口(Creator)

声明创建对象的工厂方法,该方法将由具体的子类实现。

class Creator {
public:
    virtual Product* factoryMethod() = 0;
    virtual ~Creator() {}
};


具体工厂(Concrete Creator)

实现工厂接口,负责实例化具体的产品对象。

class ConcreteCreatorA : public Creator {
public:
    virtual Product* factoryMethod() override {
        return new ConcreteProductA();
    }
};

class ConcreteCreatorB : public Creator {
public:
    virtual Product* factoryMethod() override {
        return new ConcreteProductB();
    }
};

使用说明:


假设我们有两种产品:产品 A 和产品 B,我们希望使用工厂方法模式来创建它们。

int main() {
    Creator* creatorA = new ConcreteCreatorA();
    Creator* creatorB = new ConcreteCreatorB();

    // 通过具体工厂 A 创建产品 A
    Product* productA = creatorA->factoryMethod();
    productA->operation(); // 输出:具体产品 A 的操作

    // 通过具体工厂 B 创建产品 B
    Product* productB = creatorB->factoryMethod();
    productB->operation(); // 输出:具体产品 B 的操作

    // 释放内存
    delete creatorA;
    delete creatorB;
    delete productA;
    delete productB;

    return 0;
}

在这个例子中,我们通过具体的工厂类来创建具体的产品对象,而不是直接在客户端代码中实例化产品。这样,客户端代码可以与具体产品的实现相分离,从而使得系统更具灵活性和可扩展性。如果需要添加新的产品,只需创建一个新的具体产品类和对应的具体工厂类即可,而无需修改现有的代码。

优点

  • 客户端代码与具体产品类解耦,客户端只需要知道抽象工厂接口。
  • 系统更加灵活,扩展性强,如果需要添加新产品,只需要增加相应的具体产品类和具体工厂类。
  • 遵循开闭原则,对扩展开放,对修改关闭。

缺点

  • 如果需要添加新的抽象产品,需要修改所有具体工厂类的实现。

适用场景

  • 当一个类不知道它所必须创建的对象的类的时候。
  • 当一个类希望由它的子类来指定它所创建的对象的时候。
  • 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类负责创建对象的信息局部化的时候。

抽象工厂(Abstract Factory)

定义

抽象工厂模式是一种创建型设计模式,它提供了一种方式来封装一系列相互关联或相互依赖的对象创建,而无需指定它们具体的类。抽象工厂模式允许系统独立于具体的产品类来指定产品的创建,它包含多个工厂方法,每个工厂方法负责创建一系列产品中的一个对象。

示例

假设我们有一个应用程序,它需要使用两种不同类型的产品:Vehicle(交通工具)和Accessory(配件)。每种产品都有多种实现,例如汽车(Car)和摩托车(Motorcycle)作为Vehicle的实现,轮胎(Tire)和座椅(Seat)作为Accessory的实现。

产品接口定义

// Vehicle.h  
#ifndef VEHICLE_H  
#define VEHICLE_H  
  
class Vehicle {  
public:  
    virtual void drive() = 0;  
    virtual ~Vehicle() {}  
};  
  
#endif // VEHICLE_H  
  
// Accessory.h  
#ifndef ACCESSORY_H  
#define ACCESSORY_H  
  
class Accessory {  
public:  
    virtual void install() = 0;  
    virtual ~Accessory() {}  
};  
  
#endif // ACCESSORY_H

实现具体产品类

// Car.h  
#include "Vehicle.h"  
  
class Car : public Vehicle {  
public:  
    void drive() override {  
        std::cout << "Driving a car." << std::endl;  
    }  
};  
  
// Motorcycle.h  
#include "Vehicle.h"  
  
class Motorcycle : public Vehicle {  
public:  
    void drive() override {  
        std::cout << "Driving a motorcycle." << std::endl;  
    }  
};  
  
// Tire.h  
#include "Accessory.h"  
  
class Tire : public Accessory {  
public:  
    void install() override {  
        std::cout << "Installing tire." << std::endl;  
    }  
};  
  
// Seat.h  
#include "Accessory.h"  
  
class Seat : public Accessory {  
public:  
    void install() override {  
        std::cout << "Installing seat." << std::endl;  
    }  
};

定义抽象工厂接口

// AbstractFactory.h  
#ifndef ABSTRACTFACTORY_H  
#define ABSTRACTFACTORY_H  
  
#include "Vehicle.h"  
#include "Accessory.h"  
  
class AbstractFactory {  
public:  
    virtual ~AbstractFactory() {}  
  
    virtual Vehicle* createVehicle() = 0;  
    virtual Accessory* createAccessory() = 0;  
};  
  
#endif // ABSTRACTFACTORY_H

实现具体工厂类

// CarFactory.h  
#include "AbstractFactory.h"  
#include "Car.h"  
#include "Tire.h"  
  
class CarFactory : public AbstractFactory {  
public:  
    Vehicle* createVehicle() override {  
        return new Car();  
    }  
  
    Accessory* createAccessory() override {  
        return new Tire();  
    }  
};  
  
// MotorcycleFactory.h  
#include "AbstractFactory.h"  
#include "Motorcycle.h"  
#include "Seat.h"  
  
class MotorcycleFactory : public AbstractFactory {  
public:  
    Vehicle* createVehicle() override {  
        return new Motorcycle();  
    }  
  
    Accessory* createAccessory() override {  
        return new Seat();  
    }  
};

客户端代码使用抽象工厂

 

// main.cpp 
#include <iostream> 
#include "AbstractFactory.h" 
#include "CarFactory.h" 
#include "MotorcycleFactory.h" 


int main() { 
// 创建 CarFactory 对象,用于生产 Car 和 Tire 
AbstractFactory* carFactory = new CarFactory(); 

// 使用 CarFactory 创建 Car 和 Tire 对象 
Vehicle* car = carFactory->createVehicle(); 
Accessory* tire = carFactory->createAccessory(); 

// 使用 Car 和 Tire 对象 
car->drive(); 
tire->install(); 

// 释放对象 
delete tire; 
delete car; 
delete carFactory; 

// 创建 MotorcycleFactory 对象,用于生产 Motorcycle 和 Seat 
AbstractFactory* motorcycleFactory = new MotorcycleFactory(); 

// 使用 MotorcycleFactory 创建 Motorcycle 和 Seat 对象 
Vehicle* motorcycle = motorcycleFactory->createVehicle(); 
Accessory* seat = motorcycleFactory->createAccessory(); 

// 使用 Motorcycle 和 Seat 对象 
motorcycle->drive(); 
seat->install(); 

// 释放对象 
delete seat; 
delete motorcycle; 
delete motorcycleFactory; 

return 0; 
}

在这个例子中,客户端代码通过AbstractFactory指针来创建VehicleAccessory对象,它不需要知道具体的工厂或产品实现。这允许我们在不修改客户端代码的情况下添加新的产品族或更改现有产品族的实现。

客户端代码使用抽象工厂模式

在客户端代码中,我们使用抽象工厂接口来创建产品族。客户端代码不需要知道具体的产品类是如何实现的,只需要通过工厂接口来创建产品对象。这样,如果以后需要更改产品的实现,客户端代码不需要做任何修改。

抽象工厂模式的主要优点

  1. 封装性:客户端代码不直接与具体的产品类交互,而是通过抽象工厂接口与产品族进行交互,这增强了系统的封装性。

  2. 扩展性:如果需要添加新的产品族(例如,添加一种新型的交通工具和相应的配件),只需要创建新的具体工厂类和产品类,而不需要修改现有的代码。

  3. 解耦:抽象工厂模式将产品族的创建与客户端代码解耦,这意味着客户端代码不需要知道如何创建产品,只需要知道如何使用产品。

抽象工厂模式的适用场景

  • 当一个系统需要多个产品族,并且这些产品族需要一起使用时。
  • 当系统需要支持多种产品族,并且需要根据运行时条件选择具体的产品族时。
  • 当系统需要保持产品族之间的一致性时,因为同一个工厂方法总是创建同一族的产品。

抽象工厂模式的潜在缺点

  • 如果产品族之间完全没有关联,使用抽象工厂模式可能会增加系统的复杂性。
  • 如果产品族中的产品数量很多,那么工厂接口中会有大量的方法,这可能会使得工厂接口难以管理和使用。

总结

抽象工厂模式是一种强大的设计模式,它允许我们创建一组相互关联或依赖的对象,而不需要指定它们的具体类。通过封装产品族的创建逻辑,抽象工厂模式增强了系统的可扩展性和灵活性。当系统需要支持多个产品族,并且这些产品族之间存在关联或依赖时,使用抽象工厂模式是一个很好的选择。

02-24 21:18