设计模式:抽象工厂模式

1 概述

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

抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。根据里氏替换原则,任何接受父类型的地方,都应当能够接受子类型。因此,实际上系统所需要的,仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例。

为了更清晰地理解抽象工厂模式,需要引入两个概念:

  • 产品等级结构: 产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、TCL电视机、创维电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
  • 产品族: 产品族是指同一工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构部中,海尔电冰箱位于电冰箱产品等级结构中。

2 图解

现有两个产品族ProductA和ProductB,A1、A2与ProductA在同一产品等级结构中,B1、B2与ProductB在同一产品等级。现有两个工厂FactoryA与FactoryB,FactoryA可以生产A1、B1,Factory可以生产A2、B2。

如果要生产A1,客户需要知道生产A1的工厂,并且给其特定的参数,FactoryA才可以生产出A1。

图解抽象工厂模式

工厂方法模式包含如下角色:

  • Factory 抽象工厂角色: 声明用于创建抽象产品角色的接口。
  • ConcreteFactory 具体工厂角色(图中的FactoryA、FactoryB) 实现抽象工厂接口的具体工厂类,被应用程序调用以创建具体产品对象。
  • Product 抽象产品角色(图中的ProductA、ProductB): 负责描述其实例的公共接口。
  • ConcreteProduct 具体产品角色(图中的A1、A2、B1、B2): 实现了抽象产品角色所定义的接口 ,由具体工厂角色创建。

3 优缺点

优点:

  • 抽离了具体类的生成,使得客户并不需要知道什么被创建。
  • 可以在类的内部对产品族进行约束。
  • 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。

缺点:

  • 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品。
  • 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)。

4 应用场景

在以下情况下可以使用抽象工厂模式:

  • 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。
  • 系统中有多于一个的产品族,而每次只使用其中某一产品族。
  • 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
  • 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

5 实例

FactoryMethodUml

5.1 C++实现

  1. product.h
#ifndef PRODUCT_H
#define PRODUCT_H

#include <iostream>

// 产品基类
class ProductA
{
public:
    ProductA() {}
    virtual ~ProductA(){}

    virtual void detail() const
    {
        std::cout << "This is the base class of productA." << std::endl;
    }
};

class ProductB
{
public:
    ProductB() {}
    virtual ~ProductB(){}

    virtual void detail() const
    {
        std::cout << "This is the base class of productB." << std::endl;
    }
};

// 产品A1
class ProductA1 : public ProductA
{
public:
    ProductA1() {}
    ~ProductA1() {}

    virtual void detail() const
    {
        std::cout << "This is ProductA1." << std::endl;
    }
};

// 产品A2
class ProductA2 : public ProductA
{
public:
    ProductA2() {}
    ~ProductA2() {}

    virtual void detail() const
    {
        std::cout << "This is ProductA2." << std::endl;
    }
};

// 产品B1
class ProductB1 : public ProductB
{
public:
    ProductB1() {}
    ~ProductB1() {}

    virtual void detail() const
    {
        std::cout << "This is ProductB1." << std::endl;
    }
};

// 产品B2
class ProductB2 : public ProductB
{
public:
    ProductB2() {}
    ~ProductB2() {}

    virtual void detail() const
    {
        std::cout << "This is ProductB2." << std::endl;
    }
};

#endif // PRODUCT_H
  1. factory.h
#ifndef FACTORY_H
#define FACTORY_H

#include "product.h"

// 工厂基类
class Factory
{
public:
    Factory(){}
    virtual ~Factory(){}

    static ProductA* produceA()
    {
        return NULL;
    }

    static ProductB* produceB()
    {
        return NULL;
    }
};

// 工厂A
class FactoryA : public Factory
{
public:
    FactoryA();
    virtual ~FactoryA();

    static ProductA* produceA()
    {
        return new ProductA1();
    }

    static ProductB* produceB()
    {
        return new ProductB1();
    }
};

// 工厂B
class FactoryB : public Factory
{
public:
    FactoryB();
    virtual ~FactoryB();

    static ProductA* produceA()
    {
        return new ProductA2();
    }

    static ProductB* produceB()
    {
        return new ProductB2();
    }
};


#endif // FACTORY_H
  1. main.cpp
#include <iostream>

#include "factory.h"

using namespace std;

int main()
{
    cout << "There are what FactoryA produces." << endl;
    ProductA* productA1 = NULL;
    productA1 = FactoryA::produceA();
    productA1->detail();
    cout << "======================" << endl;

    ProductB* productB1 = NULL;
    productB1 = FactoryA::produceB();
    productB1->detail();
    cout << "======================" << endl;

    cout << "There are what FactoryB produces." << endl;
    ProductA* productA2 = NULL;
    productA2 = FactoryB::produceA();
    productA2->detail();
    cout << "======================" << endl;

    ProductB* productB2 = NULL;
    productB2 = FactoryB::produceB();
    productB2->detail();
    cout << "======================" << endl;

    delete productA1;
    delete productB1;
    delete productA2;
    delete productB2;

    return 0;
}

运行结果:

C++运行结果

5.2 Python代码

#-*- coding: utf-8 -*-

'''
  抽象工厂模式
'''

class ProductA:
    '''
    产品A基类
    '''
    def detail(self):   
        print('This is the base class of productA')

class ProductB:
    '''
    产品B基类
    '''
    def detail(self):   
        print('This is the base class of productB')

class ProductA1(ProductA):
    '''
    产品A1
    '''
    def detail(self):   
        print('This is ProductA1.')

class ProductA2(ProductA):
    '''
    产品A2
    '''
    def detail(self):   
        print('This is ProductA2.')

class ProductB1(ProductB):
    '''
    产品B1
    '''
    def detail(self):   
        print('This is ProductB1.')

class ProductB2(ProductB):
    '''
    产品B2
    '''
    def detail(self):   
        print('This is ProductB2.')


class Factory:
    '''
    工厂基类
    '''
    def produceA(self):
        return None

    def produceB(self):
        return None

class FactoryA(Factory):
    '''
    工厂A
    '''
    def produceA(self):
        return ProductA1()

    def produceB(self):
        return ProductB1()

class FactoryB(Factory):
    '''
    工厂B
    '''
    def produceA(self):
        return ProductA2()

    def produceB(self):
        return ProductB2()

def main():
    print('There are what FactoryA produces.')
    fA = FactoryA()
    productA1 = fA.produceA()
    productA1.detail()
    print('======================')
    productB1 =fA.produceB()
    productB1.detail()
    print('======================')

    print('There are what FactoryB produces.')
    fB = FactoryB()
    productA2 = fB.produceA()
    productA2.detail()
    print('======================')
    productB2 =fB.produceB()
    productB2.detail()
    print('======================')

if __name__ == '__main__':
    main()

运行结果:

原文发布于微信公众号 - C与Python实战(CPythonPractice)

原文发表时间:2018-04-03

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Python小屋

Python实现大自然数分解为最多4个平方数之和(1)

问题描述:任意大自然数,总是能分解为最多4个平方数的和,所谓平方数是指它是一个自然数的平方。例如:72884 = 4^2 + 138^2 + 232^2,337...

2754
来自专栏Web行业观察

盘点那些奇形怪状的编程语言

有的语言是多面手,在很多不同的领域都能派上用场。这类编程语言叫 general-purpose language,简称 GPL。大家学过的编程语言很多都属于这一...

2882
来自专栏wym

HDU 1166 敌兵布阵

http://acm.hdu.edu.cn/showproblem.php?pid=1166

982
来自专栏牛客网

阿里 Java研发工程师[内推] 电话面试

3月20号 阿里巴巴 Java研发工程师[内部推荐] 电话面试 1. 自我介绍(问了我哪里人、去杭州工作有没有问题、什么时间可以去实习) 2. 介绍一下自己做过...

4619
来自专栏数据结构与算法

1095 火星人

1095 火星人 2004年NOIP全国联赛普及组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 D...

36110
来自专栏Albert陈凯

Scala兴衰史:暂时的没落或许是一个新的开始

5年前,Scala 似乎曾要成为编程语言中下一个佼佼者,因为它能够优雅得使用面向对象编程范式进行函数编程。 现如今,随着像 LinkedIn 和 Yammer ...

3824
来自专栏专注研发

poj-1006-Biorhythms

人生来就有三个生理周期,分别为体力、感情和智力周期,它们的周期长度为23天、28天和33天。每一个周期中有一天是高峰。在高峰这天,人会在相应的方面表现出色。例如...

961
来自专栏王杰的专栏

最快速的视野管理算法

本文提出一种利用无序数组、双向链表、位标记进行视野管理的算法,可以将每次增、删、查视野列表的复杂度降为O(1)。

5294
来自专栏IT笔记

聊聊JAVA中 String类为什么不可变

前言 "我的风格比较偏传统和经典" 小明说,"我们在打扮自己的问题上还是蛮冒险的...我觉得当你是只狗的时候,穿什么都hold的住!" ? 哈哈哈,脱离单身狗快...

42119
来自专栏python学习之旅

测试工程师的一些面试题目(python)和总结

    1、输入:JSON {"a":"aa","b":"bb","c":{"d":"dd","e":"ee"}}   输出:字典 {'a': 'aa', 'b...

4732

扫码关注云+社区

领取腾讯云代金券