设计模式(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]设计模式(十三)抽象工厂模式

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java架构沉思录

聊聊设计模式之工厂方法模式

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

1133
来自专栏前端儿

苹果

ctest有n个苹果,要将它放入容量为v的背包。给出第i个苹果的大小和价钱,求出能放入背包的苹果的总价钱最大值。

1042
来自专栏华章科技

值得收藏的Python小技巧:这17个骚操作你都OK吗?

导读:Python 是一门非常优美的语言,其简洁易用令人不得不感概人生苦短。在本文中,作者 Gautham Santhosh 带我们回顾了 17 个非常有用的 ...

3073
来自专栏带你撸出一手好代码

lambda表达式杂谈

上面的数据存放着一组人员姓名、年龄、性别相关的信息。 现在有一个需求, 获得年龄20岁以上,性别为女的人的姓名。 看到需求后, 很多人脑袋中产生的解决方案可能是...

3394
来自专栏CSDN技术头条

关于设计模式的思考

为什么叫设计模式 什么是设计模式 设计模式最初是被 GoF 于1995年提出的。GoF 全称是Gang of Four(四人帮),即 Erich Gamma,R...

3726
来自专栏编程微刊

2018年各大互联网前端面试题二(滴滴打车)

4112
来自专栏玄魂工作室

如何学python 第十七课 类-面向对象的概念

欢迎回来。今天要说的东西将会改变我们写程序的方式。今天我们介绍‘类’(class)。 概述 什么叫‘类’?类,类型。变量类型。从日常生活的感觉来说,‘类’其实...

2724
来自专栏java工会

深入浅出设计模式-抽象工厂模式

2314
来自专栏贾老师の博客

浮点数存储格式

1323
来自专栏机器学习算法与Python学习

Python技巧 101:这17个骚操作你都Ok吗

Python 是一门非常优美的语言,其简洁易用令人不得不感概人生苦短。在本文中,作者 Gautham Santhosh 带我们回顾了 17 个非常有用的 Pyt...

1134

扫码关注云+社区

领取腾讯云代金券