设计模式读书笔记4-抽象工厂模式

上一篇的工厂方法模式引入了工厂等级结构,解决了在原来简单工厂模式中工厂类职责太重的原则,但是由于工厂方法模式的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,从而增加系统开销。那么,我们应该怎么来重构?似乎,我们可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产,这就是本次将要学习的抽象工厂模式的基本思想。

抽象工厂模式(Abstract Factory)    学习难度:★★★★☆  使用频率:★★★★★

1 抽象模式引入

  人是造出来了,世界也热闹了,可是低头一看,清一色的类型,缺少关爱,喜怒哀乐,女蜗一想,忘记定义性别了,那么该肿么办呢?抹掉重来?由于之前的准备工作花费了大量的工作,比如准备黄土,八卦炉等,重头再来,几乎不可能。

生产工具该如何改造?现在只有一个设备,要么造出全部男性,要么造出全部女性?那么要实现,做出如下改造:

把原先的八卦炉拆开,一分为2,一个改造成男性八卦炉,一个改造成女性八卦

# 2 抽象工厂模式介绍

## 2.1 理清产品等级与产品族

产品等级:
产品等级即产品的继承结构,例如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌电视机则是子类。

产品族:
产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组,例如海尔电器厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,而海尔电冰箱则位于电冰箱产品等级结构中,他们俩构成了一个产品族。

产品等级与产品族的示意图如下图所示:
381412-20170430001706928-963960353.png
可以看出,当系统所提供的工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时,就可以使用抽象工厂模式。抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形式。

2.2 抽象工厂模式概述

抽象工厂模式为创建一组对象提供了一种方案,与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一族产品。其定义如下:

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。

抽象工厂模式的通用类图:
70

  1. Abstract Factory (抽象工厂角色):声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
  2. Concrete Factory (具体工厂角色):实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族。
  3. Abstract Product (抽象产品角色):为每种产品声明接口,在抽象产品中声明了所有的业务方法。
  4. Concrete Product (具体产品角色):定义具体工厂生产的具体产品对象,实现在抽象产品接口中声明的业务方法。

那么按照上面的设计方案,看看新添加男女性别之后的设计会是什么样的呢?

2.2.1 抽象产品

抽象产品结构

typedef struct _Human Human;
struct _Human
{
    void (*getColor)(void);
    void (*talk)(void);
    void (*getSex)(void);
};

typedef struct _AbstractBlackHuman AbstractBlackHuman;
struct _AbstractBlackHuman
{
    Human human;
    void (*BlackHumanDelete)(AbstractBlackHuman *pBlackHuman);
};

抽象产品实现

void BlackGetColor(void)
{
    printf("black get color\n");
}

void BlackTalk(void)
{
    printf("black talk\n");
}

void BlackHumanDelete(AbstractBlackHuman *pBlackHuman)
{
    if(!pBlackHuman)
    {
        free(pBlackHuman);
        pBlackHuman = NULL;
    }

    return;
}

AbstractBlackHuman *CreateBlackHuman(void)
{
    AbstractBlackHuman *pBlackHuman        = (AbstractBlackHuman *)malloc(sizeof(AbstractBlackHuman));
    pBlackHuman->human.getColor    = BlackGetColor;
    pBlackHuman->human.talk        = BlackTalk;
    pBlackHuman->BlackHumanDelete  = BlackHumanDelete;

    return pBlackHuman;
}

那么其他的白人,黄人采用同样的代码即可,每个抽象类都有两个实现,分别实现公共的最细节、最具体的事物。下面来看看具体的产品类

2.2.2 具体产品

具体产品结构

typedef struct _FemaleWhiteHuman FemaleWhiteHuman;
struct _FemaleWhiteHuman
{
    AbstractWhiteHuman *whiteHuman;  /*继承白色人种父类*/
    void (*getSex)(void);
    void (*DeleteFemaleWhiteHuman)(FemaleWhiteHuman *pFemaleWhiteHuman);
};

具体产品实现

void FemaleWhiteHumanGetSex(void)
{
    printf("White female human\n");
}

void FemaleWhiteHumanDelete(FemaleWhiteHuman *pFemaleWhiteHuman)
{
    if(!pFemaleWhiteHuman)
    {
        free(pFemaleWhiteHuman);
        pFemaleWhiteHuman = NULL;
    }

    return;
}

FemaleWhiteHuman *CreateFemaleWhiteHuman(void)
{
    FemaleWhiteHuman *pFemaleWhiteHuman      = (FemaleWhiteHuman *)malloc(sizeof(FemaleWhiteHuman));
    if(!pFemaleWhiteHuman)
    {
        return NULL;
    }
    pFemaleWhiteHuman->whiteHuman                = CreateWhiteHuman();
    pFemaleWhiteHuman->DeleteFemaleWhiteHuman    = FemaleWhiteHumanDelete;
    pFemaleWhiteHuman->getSex                    = FemaleWhiteHumanGetSex;
    pFemaleWhiteHuman->whiteHuman->human.getSex  = pFemaleWhiteHuman->getSex; 

    return pFemaleWhiteHuman;
}

具体的实现结构实现性别定义,其他的黑人,黄种人代码类似,不重复编写。到目前为止,我们已经把真实的世界人定义出来了,剩下的工作就是怎么制造人,八卦炉的定义就出炉了。

2.2.3 抽象工厂

typedef struct _HumanFactory HumanFactory;
struct _HumanFactory
{
    Human (*CreateYellowHuman)(void);
    Human (*CreateWhiteHuman)(void);
    Human (*CreateBlackHuman)(void);
    void (*DeleteHumanFactory)(HumanFactory *pHumanFactory);
};

在接口中,我们可以看到抽象工厂,八卦炉可以生产不同肤色的人,那么它需要几个八卦炉呢?两个,分别是男性和女性
男性工厂抽象:

typedef struct _MaleFactory MaleFactory;
struct _MaleFactory
{
    HumanFactory humanFactory;
};

男性具体产品厂实现

Human MaleFactoryCreateWhite(void)
{
    Human pHuman;
    pHuman = CreatemaleBlackHuman()->BlackHuman->human;
    return pHuman;
}
 
Human MaleFactoryCreateBlack(void)
{
    Human pHuman;
    pHuman = CreateFemaleBlackHuman()->BlackHuman->human;
    return pHuman;
}
 
Human MaleFactoryCreateYellow(void)
{
    Human pHuman;
    pHuman = CreatemaleYellowHuman()->YellowHuman->human;
    return pHuman;
}
 
 
MaleFactory *CreateMaleFactory(void)
{
    MaleFactory *pMaleFactory = (MaleFactory *)CreateHumanFactory();
    if(NULL == pMaleFactory)
    {
        return pMaleFactory;
    }
    pMaleFactory->humanFactory.CreateYellowHuman = MaleFactoryCreateYellow;
    pMaleFactory->humanFactory.CreateWhiteHuman = MaleFactoryCreateWhite;
    pMaleFactory->humanFactory.CreateBlackHuman = MaleFactoryCreateBlack;
    return pMaleFactory;
}

客户端代码

void main(void)
{
    Human pfemaleWhiteHuman;
    Human pmaleWhiteHuman;
    HumanFactory pMaleHumanFactory;
    HumanFactory pFemaleHumanFactory;
 
    /*第一条生产线, 男性生产线*/
    pMaleHumanFactory = CreateMaleFactory()->humanFactory;
 
    /*第二条生产线,女性生产线*/
    pFemaleHumanFactory = CreateFemaleFactory()->humanFactory;
 
 
    /*工厂开始工作*/
    pfemaleWhiteHuman = pFemaleHumanFactory.CreateWhiteHuman();
    printf("--write female--\n");
    pfemaleWhiteHuman.getColor();
    pfemaleWhiteHuman.talk();
    pfemaleWhiteHuman.getSex();
 
 
    pmaleWhiteHuman = pMaleHumanFactory.CreateWhiteHuman();
    printf("--write male--\n");
    pmaleWhiteHuman.getColor();
    pmaleWhiteHuman.talk();
    pmaleWhiteHuman.getSex();

    return;
}

3 抽象工厂的应用

3.1 抽象工厂的优点

  1. 封装性,每个产品的实现不需要高层模块的关系,它关心什么呢?关系接口,是抽象,而不关系如何创建
  2. 产品内的约束为非公开,增加新产品也很方便,无需修改已有系统,符合开闭原则
  3. 当一个产品族中的多个对象被设计称一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。

3.2 抽象工厂的缺点

封装的缺点也导致产品的扩展非常困难,)因为需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这必然会带来较大的不便,在这个角度,它违背了开闭(对扩展开放,对修改封闭)原则

3.3 抽象工厂的应用场景

  1. 抽象工厂模式的使用场景定义非常简单,一个对象族都有相同的约束条件,则可以使用抽象工厂模式
  2. 软件产品开发过程中,涉及到不同操作系统的时候,都可以考虑使用抽象工厂模式,例如一个应用,需要再3个不同的平台(windows,linux,android)上运行,你会怎么设计?分别设计3套不同应用?可以通过抽象工厂模式屏蔽掉操作系统对应用的影响。

3.3 抽象工厂模式的注意事项

抽象工厂模式的缺点是扩展困难,需要注意的是产品族扩展困难,而不是产品等级,在该模式下,产品等级是非常容易扩展的,增加一个产品等级,只需要增加工厂类负责新增加出来的产品生产任务即可。

4 参考资料

秦晓波, 《设计模式之禅》

刘伟,《设计模式的艺术—软件开发人员内功修炼之道》

转载于:https://www.cnblogs.com/pingchangxin2018/p/9915826.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值