工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式)

1、简单工厂模式

简单工厂模式是属于创建型模式,又叫做静态工厂方法(static Factory Method)模式,简单工厂模式是由一个工厂对象决定创建出来哪一种产品类的实例.

简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一类产品类(这些产品类继承自一个父类或接口)的实例。打个比方

假设有一个工厂,他能生产出A、B两种产品。当客户需要产品的时候一定要告诉共产是哪种产品,是A还是B。当新增加一种新产品的时候,那么就要去修改工厂的类。 

简单工厂模式的核心是,对于一个父类的多个继承子类,工厂对象的工厂函数根据用户输入,自动new出一个子类对象并返回其父类的指针,这样利用父类的指针执行父类的虚函数,就可以动态绑定子类的重写函数,从而实现多态。

对于一个只拥有加减乘除运算的简单计算器,我们设计一个Operation的父类,并构造加减乘除四个类继承父类重写运算函数GetResult。然后定义工厂类中的工厂函数,其根据用户的输入new出相应的对象实例并返回其父类的指针。

UML图如下所示:

 

C++代码如下所示,其中使用了智能指针类shared_ptr,当该对象的生命期结束时,其析构函数能够自动析构掉指针所指的对象。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include  <tr1/memory>

using namespace std;

class Operation
{
    private:
        double A, B;
    public:
        double GetA() const {return A;}
        double GetB() const {return B;}
        void SetA(double x) {A=x;}
        void SetB(double y) {B=y;}
        double virtual GetResult(){return 0;}//虚函数
        Operation():A(0), B(0){}
};

class Add : public Operation//继承类,加
{
    public:
        double GetResult()
        {
            return GetA()+GetB();
        }
};

class Sub : public Operation//继承类,减
{
    public:
        double GetResult()
        {
            return GetA()-GetB();
        }
};

class Mul : public Operation//继承类,乘
{
    public:
        double GetResult()
        {
            return GetA()*GetB();
        }
};

class Div : public Operation//继承类,除
{
    public:
        double GetResult()
        {
            return GetA()/GetB();
        }
};

class SimpleFactory//简单工厂类
{
    public:
        static Operation * CreateOpeartor(char ch)//静态成员函数,返回指向对象的指针
        {
            Operation * p;//基类指针
            switch(ch)//根据输入,实例化出合适的对象
            {
                case '+':
                    p = new Add();//指向继承类对象
                    break;
                case '-':
                    p = new Sub();
                    break;
                case '*':
                    p = new Mul();
                    break;
                case '/':
                    p = new Div();
                    break;
            }
            return p;
        }
};
        
int main(int argc, char *argv[]) //客户端代码
{
    double A = 0;
    double B = 0;
    char ch = '\0';
    cin>>A>>ch>>B;

    tr1::shared_ptr<Operation> op(SimpleFactory::CreateOpeartor(ch));//使用智能指针,op指向一个由简单工厂实例化出的对象
    op->SetA(A);
    op->SetB(B);
    cout<<op->GetResult()<<endl;//根据op指向的对象类型,调用正确的GetResult()函数,动态绑定,实现多态
}
优点:
1、充分利用了多态性不管什么具体产品都返回抽象产品。

2、充分利用了封装性,内部产品发生变化时外部使用者不会受到影响。

客户端唯一需要知道的具体子类就是工厂子类。除了这点,基本是达到了依赖倒转原则的要求。   

缺点:

如果增加了新的产品,就必须得修改工厂(Factory),不满足开放封闭原则:软件实体(类、模块、函数)可以扩展,但是不可修改。

2、工厂方法模式:(使用多态)

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

在简单工厂方法中,每次添加一个产品子类都必须在工厂类中添加一个判断分支,这样违背了开放-封闭原则,因此,工厂模式就是为了解决这个问题而产生的。

既然每次都要判断,那就把这些判断都生成一个工厂子类,这样,每次添加产品子类的时候,只需再添加一个工厂子类就可以了。这样就完美的遵循了开放-封闭原则。但这其实也有问题,如果产品数量足够多,要维护的量就会增加,好在一般工厂子类只用来生成产品类,只要产品子类的名称不发生变化,那么基本工厂子类就不需要修改。每次只需要修改产品子类就可以了。

工厂方法克服了简单工厂的缺点,增加新的产品时,不必修改现存的代码,而只需增加新代码。满足开放封闭原则。

打个比方:现在有A、B两种产品,那么就开两个工厂。工厂A负责生产A产品,工厂B负责生产B产品。这时候客户不需要告诉工厂生产哪种产品了,只需要告诉工厂生产就可以了。

#include "stdafx.h"
#include<iostream>

using namespace std;

class Product//产品类接口
{
public:
    virtual void show() = 0;  
};
//A产品类
class ConcreateProductA : public Product
{
public:
    void show()//重写(覆盖)
    {
        cout << "Product_A" << endl;
    }
};
//B产品类
class ConcreateProductB : public Product
{
public:
    void show()
    {
        cout << "Product_B" << endl;
    }
};

class ProductFactory//简单工厂类接口
{
public:
    virtual Product* create() = 0;
};
//生产A产品的工厂
class ConcreateProductFactoryA : public ProductFactory//子类中决定实例化哪种对象
{
public:
    Product* create()//重写
    {
        return new ConcreateProductA();//产生A产品对象
    }
};
//生产B产品的工厂
class ConcreateProductFactoryB : public ProductFactory
{
public:
    Product* create()
    {
        return new ConcreateProductB();//产生B产品对象
    }
};

int main()//客户端代码
{
    ProductFactory* productfactoryA = new ConcreateProductFactoryA();//由工厂实例化出某一具体工厂对象
    ProductFactory* productfactoryB = new ConcreateProductFactoryB();
    Product *product=productfactoryA.create();//调用工厂中的方法,实例化具体产品对象
    product->show();//该对象再调用相应的方法,动态绑定,多态
    
    system("pause");
    return 0;
}

工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现生产类,选择判断的问题还是存在的,即,工厂方法把简单工厂的内部逻辑判断移到了客户端代码来进行,想要加功能时,本来是该工厂类的,现在是修改客户端。

3、抽象工厂模式

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

UML图:


抽象工厂模式比工厂模式更为复杂,就像上面提到的缺点一样,工厂模式和简单工厂模式要求产品子类必须要是同一类型的,拥有共同的方法,这就限制了产品子类的扩展。于是为了更加方便的扩展,抽象工厂模式就将同一类的产品子类归为一类,让他们继承同一个抽象子类,我们可以把他们一起视作一组,然后好几组产品构成一族。

1)AbstractProductA、AbstractProductB:分别代表两种不同类型的产品由具体的产品派生类对其实现

2)AbstractFactory:抽象工厂类,提供创建两种产品的接口CreateProductA和CreateProductB,由派生的各个具体工厂类对其实现

此时,客户端要使用时必须知道是哪一个工厂并且是哪一组的产品抽象类。每一个工厂子类负责产生一族产品,而子类的一种方法产生一种类型的产品。在客户端看来只有AbstractProductA和AbstractProductB两种产品,使用的时候也是直接使用这两种产品。而通过工厂来识别是属于哪一族产品。

产品ProductA1和ProductB1构成一族产品,对应于有ConcreateFactory1来创建,也就是说ConcreateFactory1总是创建的ProductA1和ProductB1的产品,在客户端看来只需要知道是哪一类工厂和产品组就可以了。一般来说, ProductA1和ProductB1都是适应同一种环境的,所以他们会被归为一族。

AbstractFactory模式关键就是将这一组对象的创建封装到一个用于创建对象的类(ConcreteFactory)中。

AbstractFactory模式和Factory最大的差别就是抽象工厂创建的是一系列相关的对象,其中创建的实现其实采用的就是Factory模式的方法,对于某个实现有一个派生出来的工厂,另一个实现有另一个派生出来的工厂。

抽象工厂需要特别注意的地方就是区分不同类型的产品和这些产品的不同实现.显而易见的,如果有n种产品同时有m种不同的实现,那么根据乘法原理可知有n*m个Factory模式的使用(需要n个产品类,m个工厂类,每个工厂类中提供生产n种产品的方法)。

AbstractFactory模式是为创建一组(有多类)相关或依赖的对象提供创建接口,而Factory模式是为一类对象提供创建接口或延迟对象的创建到子类中实现。并且可以看到,AbstractFactory模式通常都是使用Factory模式实现(ConcreteFactory1)。

常用的场景

例如Linux和windows两种操作系统下,有2个挂件A和B,他们在Linux和Windows下面的实现方式不同,ConcreateFactory1负责产生能在Linux下运行的挂件A和B,ConcreateFactory2负责产生能在Windows下运行的挂件A和B,这样如果系统环境发生变化了,我们只需要修改工厂就行了。

优点

1.封装了产品的创建,使得不需要知道具体是哪种产品,只需要知道是哪个工厂就行了。

2.可以支持不同类型的产品,使得模式灵活性更强。

3.可以非常方便的使用一族中间的不同类型的产品。

缺点

1.结构太过臃肿,如果产品类型比较多,或者产品族类比较多,就会非常难于管理。

2.每次如果添加一组产品,那么所有的工厂类都必须添加一个方法,这样违背了开放-封闭原则。所以一般适用于产品组合产品族变化不大的情况。

#include <stdio.h>

class AbstractProductA{//抽象产品类
public:
    AbstractProductA(){}
    virtual ~AbstractProductA(){}
public:
    virtual void operationA() = 0;//纯虚函数
};
class ProductA1:public AbstractProductA{//继承类,A产品类
public:
    ProductA1(){}
    virtual ~ProductA1(){}
public:
    void operationA()
    {
        fprintf(stderr,"productA1 operation!\n");
    }
};
class ProductA2:public AbstractProductA{//继承类,B产品类
public:
    ProductA2(){}
    ~ProductA2(){}
public:
    void operationA()
    {
        fprintf(stderr,"productA2 operation!\n");
    }
};

class AbstractProductB{
public:
    AbstractProductB(){}
    virtual ~AbstractProductB(){}
public:
    virtual void operationB() = 0;
};
class ProductB1:public AbstractProductB{
public:
    ProductB1(){}
    virtual ~ProductB1(){}
public:
    void operationB()
    {
        fprintf(stderr,"productB1 operation!\n");
    }
};
class ProductB2:public AbstractProductB{
public:
    ProductB2(){}
    ~ProductB2(){}
public:
    void operationB()
    {
        fprintf(stderr,"productB2 operation!\n");
    }
};

class AbstractFactory{//抽象工厂类
public:
    AbstractFactory(){}
    virtual ~AbstractFactory(){}
public:
    virtual AbstractProductA* createProductA() = 0;
    virtual AbstractProductB* createProductB() = 0;
};
class ConcreateFactory1:public AbstractFactory{//子类工厂,生产A1,B1产品
public:
    ConcreateFactory1(){}
    ~ConcreateFactory1(){}
public:
    AbstractProductA* createProductA()//生产A1
    {
        return new ProductA1();
    }
    AbstractProductB* createProductB()//生产B1
    {
        return new ProductB1();
    }
};

class ConcreateFactory2:public AbstractFactory{//子类工厂,生产A2,B2产品
public:
    ConcreateFactory2(){}
    ~ConcreateFactory2(){}
public:
    AbstractProductA* createProductA()//生产A2
    {
        return new ProductA2();
    }
    AbstractProductB* createProductB()//生产B2
    {
        return new ProductB2();
    }
};

int main(){//客户端
    AbstractFactory* factory = new ConcreateFactory1();//确定实例化哪一族产品,例如生产能在windows下运行的挂件A、B。factory指向一个ConcreateFactory1对象
    AbstractProductA* productA = factory->createProductA();//调用ConcreateFactory1中方法createProductA()产生指向ProductA1对象的指针productA
    AbstractProductB* productB = factory->createProductB();//调用ConcreateFactory1中方法createProductB()产生指向ProductB1对象的指针productB
    productA->operationA();//调用类ProductA1中的方法,多态
    productB->operationB();//调用ProductB1中的方法

    delete factory;
    factory = NULL;
    delete productA;
    productA = NULL;
    delete productB;
    productB = NULL;

    factory = new ConcreateFactory2();//生产能在linux下运行的挂件A、B
    productA = factory->createProductA();
    productB = factory->createProductB();
    productA->operationA();
    productB->operationB();

    delete factory;
    factory = NULL;
    delete productA;
    productA = NULL;
    delete productB;
    productB = NULL;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值