设计模式(6)——抽象工厂模式(Abstract Factory Pattern,创建型)

1.概述

使用设计模式可以提高代码的可复用性、可扩充性和可维护性。抽象工厂模式(Abstract Factory Pattern)属于创建型模式,为创建一组相关或者相互依赖的对象(产品族)提供一个抽象类接口,而无需指定它们的具体类。。产品族的定义是:某个具体工厂生产的所有类型的产品,比如定义了一个抽象工厂接口A,它可以生产三种产品:p1、p2、p3,而这三个产品就叫一个产品族。

抽象工厂模式可以说是工厂方法模式的升级版,当需要创建的产品有多个产品族时使用抽象工厂模式是比较好的选择。那什么是多个产品族呢?拿我们在设计模式(四)——简单工厂模式设计模式(五)——工厂方法模式中学习的生产比萨的例子来举例。我们一直都是在一个比萨店生产三种不同口味的比萨,但是不同地方的比萨店生产的同一品种的比萨点使用的原料可能存在差异。比如纽约和芝加哥的比萨店都在生产蛤蜊比萨,但是纽约喜欢薄的且靠近大海,所以使用较小的面团和新鲜的蛤蜊,芝加哥使用较大的面团和冷冻的比萨。现在使用工厂方法模式来生产原料已经满足不了需求,因为生产对象的总类太多,这一篇文章我们就用抽象工厂模式来解决这一问题。

抽象工厂模式类图结构:
这里写图片描述

在抽象工厂模式中有如下角色:
AbstractFactory:抽象工厂类,它声明了用来创建不同产品的方法。
ConcreteFactory:具体工厂类,实现抽象工厂中申明的创建产品的方法。
AbstractProduct:抽象产品类,为每种产品声明抽象描述方法。比如上图的AbstractProductA和 AbstractProductB。
ConcreteProduct:具体产品类,定义具体工厂生产的具体产品,并实现抽象产品类中申明的抽象描述方法。

2.抽象工厂模式简单实现

下面以C++来实现。首先定义抽象产品类,分别为面团Dough和蛤蜊Clam:

//面团
class Dough{
public:
    virtual string getDescription() = 0;
};

//蛤蜊
class Clam{
public:
    virtual string getDescription() = 0;
};

现在实现纽约和芝加哥两地比萨店使用的不同的具体原料类:

//纽约面团
class NewYorkDough:public Dough{
public:
    virtual string getDescription() {
        return "纽约薄面团";
    };
};
//纽约蛤蜊
class NewYorkClam:public Clam{
public:
    virtual string getDescription() {
        return "纽约新鲜蛤蜊";
    };
};

//芝加哥面团
class ChicagoDough:public Dough{
public:
    virtual string getDescription() {
        return "芝加哥厚面团";
    }
};
//芝加哥面团
class ChicagoClam:public Clam{
public:
    virtual string getDescription() {
        return "芝加哥冷冻蛤蜊";
    }
};

有了抽象产品类和具体产品类,现在来完成抽象工厂和具体工厂的设计和实现。

//抽象工厂
class AbstractFactory {
public:
    virtual Dough* createDough() = 0;
    virtual Clam* createClam() = 0;
};

//具体生产纽约比萨原料工厂
class NewYorkFactory :public AbstractFactory {
public:
    Dough* createDough() {
        return new NewYorkDough;
    }
    Clam* createClam() {
        return new NewYorkClam;
    }
};
//具体生产芝加哥比萨原料工厂
class ChicagoFactory :public AbstractFactory {
public:
    Dough* createDough() {
        return new ChicagoDough;
    }
    Clam* createClam() {
        return new ChicagoClam;
    }
};

客户端代码,使用工厂来生产具体的比萨原料。

#include <iostream>  
#include <string>
using namespace std;
int main() {
    AbstractFactory* af1 = new NewYorkFactory;
    Dough* dough1 = af1->createDough(); //生产纽约薄面团
    cout << dough1->getDescription() << endl;
    Clam* clam1 = af1->createClam();    //生产纽约新鲜蛤蜊
    cout << clam1->getDescription() << endl;

    AbstractFactory* af2 = new ChicagoFactory;
    Dough* dough2 = af2->createDough(); //生产芝加哥厚面团
    cout << dough2->getDescription() << endl;
    Clam* clam2 = af2->createClam();    //生产芝加哥冷冻蛤蜊
    cout << clam2->getDescription() << endl;
    system("pause");
}

程序运行结果:

纽约薄面团
纽约新鲜蛤蜊
芝加哥厚面团
芝加哥冷冻蛤蜊

3.抽象工厂模式的应用场景和优缺点

应用场景:
(1)一个系统不依赖于产品族实例如何被创建、组合和表达的细节。如本文例子中一个比萨店生产的比萨原料是一个产品族。
(2)系统中有多于一个产品族。一个产品族存在存在着多个抽象类,如蛤蜊基类、面团基类等。并且产品族中分属各个抽象基类的各个实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。假如各个抽象类的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点,比如我们在设计模式(五)——工厂方法模式中使用工厂方法模式来创建不同口味的比萨。

优点:
抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束。所谓的产品族,一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理。

缺点:
产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则需要修改抽象工厂类和生产该产品族的具体工厂类。所以使用抽象工厂模式时,对产品族的划分是非常重要的。

4.抽象工厂模式与工厂方法和简单工厂模式的对比

无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,在抽象工厂类中加入了一个新方法后,由于抽象工厂类中的产品构成了不同抽象基类中具体产品,具体工厂类生产的产品就组成了一个产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使提供的产品不再构成产品族之后,它就演变成了工厂方法模式。

所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。

参考文献

[1]23种设计模式(3):抽象工厂模式
[2]设计模式(十三)抽象工厂模式

©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值