设计模式 03 抽象工厂模式

发布于 2021-06-09  103 次阅读


一、意图

  提供一个接口一创建一系列相关或相互依赖的对象,而无需指定它们具体的类。

二、UML

图1
图1:抽象工厂模式UML

三、问题

  假设我们开发一些列产品,例如:椅子Chair、沙发Sofa和咖啡桌CoffeTable。现在我们有多种产品的变体:如现代Modern、维多利亚Vectorian、装饰风艺术ArtDeco等风格来生成与椅子、沙发和咖啡桌。

图2
图2:问题模型

  为了确保产品生成的风格一致,同时减少增添新产品或新风格时的代码修改量,我们引入抽象工厂模式。

四、解决方案

  首先,抽象工厂模式建议为系列中的每件产品明确声明接口(例如椅子、 沙发或咖啡桌)。然后,确保所有产品变体都继承这些接口。例如,所有风格的椅子都实现椅子接口;所有风格的咖啡桌都实现咖啡桌接口,以此类推。

图3
图3:创建接口

  接下来,我们需要声明抽象工厂——包含系列中所有产品构造方法的接口。例如 createChair创建椅子 、createSofa创建沙发和createCoffeeTable创建咖啡桌。这些方法必须返回抽象产品类型,即我们之前抽取的那些接口:椅子,沙发和咖啡桌等等。
图4
图4:抽象工厂

  那么该如何处理产品变体呢?对于系列产品的每个变体,我们都将基于抽象工厂接口创建不同的工厂类。每个工厂类都只能返回特定类别的产品,例如,现代家具工厂ModernFurnitureFactory只能创建现代椅子ModernChair、现代沙发ModernSofa和现代咖啡桌ModernCoffeeTable对象。
  客户端代码可以通过相应的抽象接口调用工厂和产品类。 你无需修改实际客户端代码, 就能更改传递给客户端的工厂类, 也能更改客户端代码接收的产品变体。
图5
图5

  假设客户端想要工厂创建一把椅子。客户端无需了解工厂类,也不用管工厂类创建出的椅子类型。无论是现代风格,还是维多利亚风格的椅子,对于客户端来说没有分别,它只需调用抽象椅子接口就可以了。 这样一来,客户端只需知道椅子以某种方式实现了sitOn坐下方法就足够了。此外,无论工厂返回的是何种椅子变体,它都会和由同一工厂对象创建的沙发或咖啡桌风格一致。
  最后一点说明: 如果客户端仅接触抽象接口, 那么谁来创建实际的工厂对象呢? 一般情况下, 应用程序会在初始化阶段创建具体工厂对象。 而在此之前, 应用程序必须根据配置文件或环境设定选择工厂类别。

五、实例

#include <iostream>
#include <map>
#include <memory>

/* ==============================*/
/* ===== Product 00 : Chair =====*/
/* ==============================*/
class AbstractChair
{
public:
    virtual ~AbstractChair() {}

    virtual std::string GetChairName() const = 0;
};

class ArtDecoChair : public AbstractChair
{
public:
    std::string GetChairName() const override
    {
        return "Art Deco Chair";
    }
};

class VictorianChair : public AbstractChair
{
public:
    std::string GetChairName() const override
    {
        return "Victorian Chair";
    }
};

class ModernChair : public AbstractChair
{
public:
    std::string GetChairName() const override
    {
        return "Modern Chair";
    }
};

/* =============================*/
/* ===== Product 02 : Sofa =====*/
/* =============================*/
class AbstractSofa
{
public:
    virtual ~AbstractSofa() {}

    virtual std::string GetSofaName() const = 0;
};

class ArtDecoSofa : public AbstractSofa
{
    std::string GetSofaName() const override
    {
        return "Art Deco Sofa";
    }
};

class VictorianSofa : public AbstractSofa
{
    std::string GetSofaName() const override
    {
        return "Victorian Sofa";
    }
};

class ModernSofa : public AbstractSofa
{
    std::string GetSofaName() const override
    {
        return "Modern Sofa";
    }
};

/* ===================*/
/* ===== Factory =====*/
/* ===================*/
class AbstractFactory
{
public:
    virtual AbstractChair* CreateChair() const = 0;
    virtual AbstractSofa* CreateSofa() const = 0;
};

class ArtDecoFactory : public AbstractFactory
{
public:
    AbstractChair* CreateChair() const override
    {
        return new ArtDecoChair();
    }

    AbstractSofa* CreateSofa() const override
    {
        return new ArtDecoSofa();
    }
};

class VictorianFactory : public AbstractFactory
{
public:
    AbstractChair* CreateChair() const override
    {
        return new VictorianChair();
    }

    AbstractSofa* CreateSofa() const override
    {
        return new VictorianSofa();
    }
};

class ModernFactory : public AbstractFactory
{
    AbstractChair* CreateChair() const override
    {
        return new ModernChair();
    }

    AbstractSofa* CreateSofa() const override
    {
        return new ModernSofa();
    }
};

void Cilent_ShowProduct(const AbstractFactory& p_factory)
{
    const AbstractChair* chair = p_factory.CreateChair();
    const AbstractSofa* sofa = p_factory.CreateSofa();

    std::cout << chair->GetChairName() << std::endl;
    std::cout << sofa->GetSofaName() << std::endl;

    delete chair;
    delete sofa;
}

int main()
{
    std::cout << "now is Art Deco Factory" << std::endl;
    const ArtDecoFactory* artdecoFactory = new ArtDecoFactory();
    Cilent_ShowProduct(*artdecoFactory);

    return 0;
}