工厂模式(创建型)

前言


上一篇简要介绍了OOD的设计原则及设计模式的基本概念,从本篇开始介绍包括创建型(5)&结构型(7)&行为型(11)总共23种基本的设计模式和简单的C++代码实现。本篇介绍工厂模式,包括以下三种模式:

  • 简单工厂模式
  • 工厂方法模式
  • 抽象工厂模式

简单工厂模式


在介绍工厂方法模式之前,先介绍下简单工厂模式

意图

定义一个创建对象的工厂类,并提供相应的创建对象的接口,简单工厂模式并不把一个类的实例化延迟到子类(也不存在子类)

参与者

  • Concrete Factory
    提供创建对象的接口,可以使用一个create接口来进行硬编码,也可以针对不同具体产品提供不同的create接口

  • Abstract Product
    抽象产品类,可以派生出多个具体产品

  • Concrete Product
    具体产品类

模式结构

simple_factory

代码实现

  1. 首先定义一个抽象产品类,只提供一个简单的Show()接口显示不同产品类型的打印:

    1
    2
    3
    4
    5
    class AbstractProduct
    {
    public:
    virtual void Show() = 0;
    };
  2. 然后分别根据抽象产品派生两个不同的产品类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class ProductA: public AbstractProduct
    {
    public:
    void Show()
    {
    cout << "I am Product A" << endl;
    }
    };

    class ProductB: public AbstractProduct
    {
    public:
    void Show()
    {
    cout << "I am Product B" << endl;
    }
    };
  3. 最后定义一个简单的工厂类,并提供一个静态的create方法,通过硬编码的方法来创建对象:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    class SimpleFactory
    {
    public:
    static AbstractProduct* CreateProduct(int ProductType)
    {
    switch (ProductType)
    {
    case 1:
    return new ProductA();
    break;
    case 2:
    return new ProductB();
    break;
    default:
    return NULL;
    break;
    }
    }
    };

    //除了硬编码还可以通过根据不同的产品提供不同create接口来实现:

    class SimpleFactory
    {
    public:
    static AbstractProduct* CreateProductA()
    {
    return new ProductA();
    }
    static AbstractProduct* CreateProductB()
    {
    return new ProductB();
    }
    };
  4. 测试简单工厂:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void SimpleFactoryTest()
    {
    AbstractProduct *pPA = SimpleFactory::CreateProduct(1);
    // AbstractProduct *pPA = SimpleFactory::CreateProductA;
    pPA->Show();
    AbstractProduct *pPB = SimpleFactory::CreateProduct(2);
    // AbstractProduct *pPA = SimpleFactory::CreateProductB;
    pPB->Show();

    delete pPA; pPA = NULL;
    delete pPB; pPB = NULL;
    };

运行结果:

I am Product A
I am Product B

适用场景

比较简单的对象创建

优缺点

  • 优点:简单
  • 缺点:要增加新的产品类型时,就需要修改工厂类,这就违反了开放封闭原则

工厂方法模式


如果想在增加新的产品类型时候,不需要修改原来的工厂类,从而符合开放封闭原则,可以考虑使用工厂方法模式类定义一个抽象接口,并增加新的产品工厂类即可

意图

定义一个用于创建对象的接口让子类决定实例化哪一个类。工厂模式使一个类的实例化延迟到其子类

参与者

  • Abstract Factory
    声明工厂方法,该方法返回一个Abstract Product类型的对象。Abstract Factory也可以定义一个工厂方法的缺省实现,它返回一个缺省的Concrete Product对象;
    工厂接口是工厂方法模式的核心,与调用者直接交互用来提供产品

  • Concrete Factory
    Concrete Factory决定如何实例化产品,是实现扩展的途径,需要有多少种产品,就需要有多少个具体的工厂实现;
    重定义工厂方法以返回一个Concrete Product实例;

  • Abstract Product
    抽象产品类,可以派生出多个具体产品

  • Concrete Product
    具体产品类

模式结构

factory_method

代码实现

  1. 抽象产品和具体的产品代码见上节的简单工厂模式代码实现部分

  2. 与简单工厂模式不同的是,新增加了个抽象工厂类,提供一个virtual的create产品方法:

    1
    2
    3
    4
    5
    class AbstractFactory
    {
    public:
    virtual AbstractProduct* CreateProduct() = 0;
    };
  3. 然后针对不同的具体产品,定义不同的具体工厂类,并override抽象工厂的create产品方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // 产品类A的具体工厂A
    class FactoryA: public AbstractFactory
    {
    public:
    AbstractProduct* CreateProduct()
    {
    return new ProductA();
    }
    };

    // 产品类B的具体工厂B
    class FactoryB: public AbstractFactory
    {
    public:
    AbstractProduct* CreateProduct()
    {
    return new ProductB();
    }
    };
  4. 测试工厂方法模式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    void FactoryMethodTest()
    {
    AbstractFactory *pFA = new FactoryA(); // 抽象的工厂指针指向具体的工厂对象
    AbstractProduct *pPA = pFA->CreateProduct(); // 抽象的产品指针具体的产品对象
    pPA->Show();

    AbstractFactory *pFB = new FactoryB();
    AbstractProduct *pPB= pFB->CreateProduct();
    pPB->Show();

    delete pFA; pFA = NULL;
    delete pPA; pPA = NULL;
    delete pFB; pFB = NULL;
    delete pPB; pPB = NULL;
    }

运行结果:

I am Product A
I am Product B

使用场景

  • 当一个类不知道它所必须创建的对象的类的时候
  • 当一个类希望由它的子类来指定它所创建的对象的时候
  • 工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现的尤为明显。
    假如调用者自己组装产品需要增加依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度
  • 需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装

优缺点

  • 优点:
    • 可以使代码结构清晰,有效地封装变化。在编程中,产品类的实例化有时候是比较复杂和多变的,通过工厂模式,将产品的实例化封装起来,使得调用者根本无需关心产品的实例化过程,
      只需依赖工厂即可得到自己想要的产品
    • 对调用者屏蔽具体的产品类。如果使用工厂模式,调用者只关心产品的接口就可以了,至于具体的实现,调用者根本无需关心。
    • 降低耦合度。产品类的实例化通常来说是很复杂的,它需要依赖很多的类,而这些类对于调用者来说根本无需知道,如果使用了工厂方法,我们需要做的仅仅是实例化好产品类,然后交给调用者使用。对调用者来说,产品所依赖的类都是透明的,即使变更了具体的实现,对调用者来说没有任何影响
  • 缺点:
    新增加一个产品类型就需要引入一个工厂类,会增加系统的复杂度

抽象工厂模式


意图

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

参与者

  • Abstract Factory
    声明工厂方法,声明一个创建抽象产品对象的操作接口,通常含有多个创建接口对应于不同的产品族

所谓的产品族(也称为产品系列),是指位于不同产品等级结构中功能相关联的产品组成的家族,在编程中,通常一个产品结构,表现为一个接口或者抽象类

  • Concrete Factory
    Concrete Factory决定如何实例化产品,是实现扩展的途径,一般而言,多少种产品系列就有多少个具体工厂
    重定义工厂方法以返回一个Concrete Product实例;

  • Abstract Product
    抽象产品类,可以派生出多个具体产品

  • Concrete Product
    具体产品类

模式结构

abstract_factory

代码实现

1.抽象产品A(对应一个产品结构)

1
2
3
4
5
class AbstractProductA
{
public:
virtual void ShowA() = 0;
};

2.抽象产品A派生的具体产品A1,A2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class ProductA1 : public AbstractProductA
{
public:
void ShowA()
{
cout << "I am Product A1" << endl;
}
};

class ProductA2 : public AbstractProductA
{
public:
void ShowA()
{
cout << "I am Product A2" << endl;
}
};

3.抽象产品B(对应第二个产品结构)

1
2
3
4
5
class AbstractProductB
{
public:
virtual void ShowB() = 0;
};

4.抽象产品B派生的具体产品B1,B2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class ProductB1: public AbstractProductB
{
public:
void ShowB()
{
cout << "I am Prouduct B1" << endl;
}
};

class ProductB2: public AbstractProductB
{
public:
void ShowB()
{
cout << "I am Prouduct B2" << endl;
}
};

5.抽象工厂,包括创建多个不同的产品等级的抽象接口,此类的产品等级分别为A,B

1
2
3
4
5
6
class AbstractFactoryAB
{
public:
virtual AbstractProductA* CreateProductA() = 0;
virtual AbstractProductB* CreateProductB() = 0;
};

6.具体工厂,包含具体工厂1和工厂2,分别生成产品族1(A1,B1)和产品族2(A2,B2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Factory1: public AbstractFactoryAB
{
public:
AbstractProductA* CreateProductA()
{
return new ProductA1();
}
AbstractProductB* CreateProductB()
{
return new ProductB1();
}
};

class Factory2: public AbstractFactoryAB
{
public:
AbstractProductA* CreateProductA()
{
return new ProductA2();
}
AbstractProductB* CreateProductB()
{
return new ProductB2();
}
};

7.测试抽象工厂模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void AbstractFactoryTest()
{
// 工厂1生产产品族A1,B1
AbstractFactoryAB *pF1 = new Factory1();
AbstractProductA *pPA1 = pF1->CreateProductA();
pPA1->ShowA();
AbstractProductB *pPB1 = pF1->CreateProductB();
pPB1->ShowB();

// 工厂2生产产品族A2,B2
AbstractFactoryAB *pF2 = new Factory2();
AbstractProductA *pPA2 = pF2->CreateProductA();
pPA2->ShowA();
AbstractProductB *pPB2 = pF2->CreateProductB();
pPB2->ShowB();

delete pF1; pF1 = NULL;
delete pPA1; pPA1 = NULL;
delete pPB1; pPB1 = NULL;
delete pF2; pF2 = NULL;
delete pPA2; pPA2 = NULL;
delete pPB2; pPB2 = NULL;
}

运行结果:

I am Product A1
I am Prouduct B1
I am Product A2
I am Prouduct B2

使用场景

当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。
假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点。

优缺点

  • 优点:
    抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束。产品族一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理
  • 缺点:
    产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的

简单工厂模式&工厂方法模式&抽象工厂模式的区别

  • 此三者目的都是为了使一个系统独立于它的产品的创建、组合过程
  • 简单工厂模式一般只提供一个具体的工厂,没有抽象的工厂;而工厂方法模式&抽象工厂模式提供了抽象的工厂,更符合开闭原则
  • 抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象
  • 工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构
  • 工厂方法模式所提供的具体产品是衍生自一个等级结构(接口或抽象类);抽象工厂模式所提供的具体产品则是衍生自不同的等级结构(接口或抽象类)