设计模式 c++版(5)——抽象工厂模式

定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类


示例一:女娲造人扩展

造出来黑、白、黄种人,分别有性别分类
类图说明:一个接口,多个抽象类,N个实现类,每个人种都是一个抽象类,性别是在各个实现类中实现的。

1. 结构说明:

HumanFactory 接口,这个接口中定义了三个方法,分别用来产生三个不同肤色的人种
FemalFactory 和 MaleFactory 两个实现类,实现肤色、性别定义
AbstractBlackHuman 每个抽象类都有两个实现类,分别实现公共的、最具体的事物:肤色和语言。

2. 女娲造人类图9-2:

3. 女娲造人,代码清单9-2:
 

#include <QCoreApplication>
#include <QDebug>

//////    **********  1. 女娲造人扩展,代码清单9-1:***************//


class Human
{
public:
    virtual void    getColor() = 0;
    virtual void    talk()     = 0;
    virtual void    getSex()   = 0;
};

class YellowHuman:public Human
{
public:
    virtual void    getColor()  {qDebug() << "YellowHuman color: yellow";}
    virtual void    talk()      {qDebug() << "YellowHuman talk: ccc";}    
};

class FYellowHuman:public YellowHuman 
{
public:
    virtual void    getSex()    {qDebug() << "*FemalYellowHuman*";} 
};

class HumanFactory
{
public:
    virtual Human* createYellowHuman() = 0;
};

class FemalFactory:public HumanFactory
{
public:
    virtual Human* createYellowHuman() 
    {  
        FYellowHuman *hu = new FYellowHuman();
        Human *human = dynamic_cast<Human*>(hu);
        return human;
    }
};

int main()
{
    FemalFactory factory;
    
    Human *human = factory.createYellowHuman();
    human->getSex();
    human->getColor();
    human->talk();
    
    return 0;
}


4. 这里只写出了制造女性黄种人的示例代码,其他类同


示例二:通用抽象工厂模式


1. 抽象工厂模式通用类图,类图9-3

说明:抽象工厂模式是工厂模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。


2. 抽象工厂模式通用源码类图,类图9-4


说明:有两个相互影响的产品线(也叫做产品族),例如制造汽车的左侧门和右侧门,这两个应该是数量相等的——两个对象之间的约束,每个型号的车门都是不一样的,这是产品等级结构约束的。


3. 通用抽象工厂模式,代码清单9-2:
 

#include <QCoreApplication>
#include <QDebug>

//////    **********  2.抽象工厂模式的通用源码 ,代码清单9-1:***************//

//ProductA
class AbstractProductA
{
public:
    void            shareMethod(){}
    virtual void    doSomething() = 0;
};

class ProductA1:public AbstractProductA
{
public:
    virtual void    doSomething(){qDebug() << "ProductA1 method";}
};

class ProductA2:public AbstractProductA
{
public:
    virtual void    doSomething(){qDebug() << "ProductA2 method";}
};

//ProductB
class AbstractProductB
{
public:
    void            shareMethod(){}
    virtual void    doSomething() = 0;
};

class ProductB1:public AbstractProductB
{
public:
    virtual void    doSomething(){qDebug() << "ProductB1 method";}
};

class ProductB2:public AbstractProductB
{
public:
    virtual void    doSomething(){qDebug() << "ProductB2 method";}
};

//Creator
class AbstractCreator
{
public:
    virtual AbstractProductA* createProductA() = 0;
    virtual AbstractProductB* createProductB() = 0;
};

class Creator1:public AbstractCreator
{
public:
    virtual AbstractProductA* createProductA()
    {
        ProductA1 *a1 = new ProductA1();
        AbstractProductA *product = dynamic_cast<AbstractProductA*>(a1);
        return product;
    }

    virtual AbstractProductB* createProductB()
    {
        ProductB1 *b1 = new ProductB1();
        AbstractProductB *product = dynamic_cast<AbstractProductB*>(b1);
        return product;
    }
};

class Creator2:public AbstractCreator
{
public:
    virtual AbstractProductA* createProductA()
    {
        ProductA2 *a2 = new ProductA2();
        AbstractProductA *product = dynamic_cast<AbstractProductA*>(a2);
        return product;
    }

    virtual AbstractProductB* createProductB()
    {
        ProductB2 *b2 = new ProductB2();
        AbstractProductB *product = dynamic_cast<AbstractProductB*>(b2);
        return product;
    }
};

int main ()
{
    Creator1 creator1;
    Creator2 creator2;
    
    AbstractProductA *a1 = creator1.createProductA();
    AbstractProductA *a2 = creator2.createProductA();
    
    AbstractProductB *b1 = creator1.createProductB();
    AbstractProductB *b2 = creator2.createProductB();
    
    a1->doSomething();
    a2->doSomething();
    b1->doSomething();
    b2->doSomething();
    
    return 0;
}




说明:场景类中,没有任何一个方法与实现类有关,对于一个产品来说,我们只要知道他的工厂方法就可以直接产生一个产品队形,无需关心他的实现类。


三、工厂方法模式的应用

优点:

  •  封装性。每个产品的实现类不是高层模块要关心的,它要关心的是接口。只要知道工厂类,就可以创建出一个需要的对象。
  •  产品族内的约束为非公开状态。具体的产品族内的约束是在工厂内实现的

 
缺点:

 产品族扩展非常困难。以通用代码为例,如果要增加一个产品C,抽象类 AbstractCreator 要增加一个方法 createProductC() ,另外两个实现类都需要修改,违反了开闭原则。

使用场景:

一个对象族(或是一组没有任何关系的对象)都有相同的约束,则可以使用抽象工厂模式。
例如:一个文本编辑器和一个图片处理器,都是软件实体,但是在*nix 下的文本编辑器和 windows 下的文本编辑器虽然功能和界面都相同,但是代码实现不同,图片处理器也有类似情况。也就具有了共同的约束条件:操作系统类型。于是我们可以使用抽象工厂模式,产生不同操作系统下的编辑器和图片处理器。

注意事项:

在抽象工厂模式的缺点中,我们提到抽象工厂模式的产品族扩展比较困难,但是产品等级容易扩展。只要增加一个工厂类负责新增加出来的产品生产任务即可。也就是说横向扩展容易,纵向扩展困难。以女娲造人为例,产品登记汇总只有男、女两个性别,需要再增加双性人,呐我们需要增加咱哥产品类,分别对应不同的肤色,然后再创建一个工厂类,专门负责不同肤色人的双性人的创建任务,完全通过扩展来实现需求的变更,从这一点上看,抽象工厂模式符合开闭原则。

四、最佳实践

在软件产品开发过程中,涉及不同操作系统的时候,都可以考虑使用抽象工厂模式。例如一个应用,需要再三个不同平台(windows 、linux 、android)上运行,可以通过抽象工厂模式屏蔽掉操作系统对应用的影响。三个不同操作系统上的软件功能、应用逻辑、UI都应该是非常类似的,唯一不同的是调用不同的工厂方法,由不同的产品类去处理与操作系统交互的信息。


参考文献《秦小波. 设计模式之禅》(第2版) (华章原创精品) (Kindle 位置 308-310). 机械工业出版社

猜你喜欢

转载自blog.csdn.net/Jecklin_online/article/details/82800591