大话设计模式---三种工厂模式

在学习的过程中,发现工厂模式有三种:简单工厂模式、工厂方法模式和抽象工厂模式
转自:专栏《《大话设计模式》C++实现》仅供学习使用!

工厂模式可以分为三类:

1)简单工厂模式(Simple Factory):不符合开放-封闭原则
2)工厂方法(Factory Method):生产单一产品
3)抽象工厂模式(Abstract Factory):生产一个产品体系

简单工厂模式有一个具体的工厂类
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
这三中设计模式是有一定的关联的。

1、简单工厂模式:

这里写图片描述
这里写图片描述
简单工厂模式:一个上帝类,能够生产A车,若有一种B车需要生产,则需要更改上帝类工厂代码

包含的角色:

简单工厂模式包含三个角色:

(1)工厂类Factory:工厂类是用来制造产品的。因此,在Factory中有一个用于制造产品的Create函数或者Generate函数之类的函数。这个函数能够根据“标识符”的不同生成不同的ConcreteProduct,当然这些ConcreteProduct都是继承自AbstractProduct的。

(2)抽象产品类AbstractProduct:抽象产品是从其他具体产品抽象出来的。抽象产品类只有一个。

(3)具体产品类ConcreteProduct:具体产品类继承自抽象产品类,可以有多个。当需要增加新的产品的时候就增加一个继承自抽象产品类的具体产品类即可。

优势:

实现了松耦合,当需要增加一种新产品(在大话设计模式中,例子是 运算Operation),只需要做两点改动:

(1)增加一个继承自抽象产品(抽象的运算)的具体产品(一种具体的运算);

(2)在工厂类中,switch中,增加一种根据标识符产生新运算的case即可。
代码:

#include <iostream>
#include <cstdlib>

using namespace std;

//抽象产品类
class Operation
{
protected:
    double numberA;
    double numberB;

public:
    double getA()
    {
        return numberA;
    }
    double getB()
    {
        return numberB;
    }
    void setA(double number)
    {
        numberA=number;
    }
    void setB(double number)
    {
        numberB=number;
    }

    virtual double GetResult()
    {
        double result=0;
        return result;
    }
};

//下面是四种具体产品类
class OperationAdd:public Operation
{
public:
    double GetResult()
    {
        double result=0;
        result=numberA+numberB;
        return result;
    }
};

class OperationSub:public Operation
{
public:
    double GetResult()
    {
        double result=0;
        result=numberA-numberB;
        return result;
    }
};

class OperationMul:public Operation
{
public:
    double GetResult()
    {
        double result=0;
        result=numberA*numberB;
        return result;
    }
};

class OperationDiv:public Operation
{
public:
    double GetResult()
    {
        double result=0;
        if(numberB!=0)
            result=numberA/numberB;
        return result;
    }
};

//工厂类   
class OperationFactory
{
public:
    Operation* createOperation(char type)
    {
        Operation* oper;
        switch(type)
        {
        case '+':
            oper=new OperationAdd;
            break;
        case '-':
            oper=new OperationSub;
            break;
        case '*':
            oper=new OperationMul;
            break;
        case '/':
            oper=new OperationDiv;
            break;
        }
        return oper;
    }
};

//客户端
void main()
{
    Operation* oper=NULL;

    OperationFactory of;
    oper=of.createOperation('/');
    oper->setA(1);
    oper->setB(2);
    cout<<oper->GetResult()<<endl;
    if(oper!=NULL)
    {
        delete oper;
        oper=NULL;
    }
    system("pause");
}

这里写图片描述

2、工厂方法模式:

工厂方法模式(Factory Method):定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法是一个类的实例化延迟到其子类。
工厂方法模式:去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。由于简单工厂模式不仅对扩展开放了,也对修改开放了(每添加一个类,就得去生成实例的工厂方法中增加新的分支),违背了“开放-封闭原则”。工厂方法把简单工厂的内部逻辑判断转移到了客户端代码来进行。缺点:每加一个产品,需要额外加一个产品工厂的类,增加了额外的开销。
这里写图片描述
这里写图片描述
包含的角色

(1)抽象工厂

(2)具体工厂

(3)抽象产品

(4)具体产品

优势

(1)工厂方法模式是对简单工厂模式的稍微的改进。工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际工作推迟到子类中。

(2)与简单工厂模式相比,制造产品的工厂类不再 只有一个,而是每种具体产品类都对应一个生产它的具体工厂类。而这些具体工厂类的共同特征再被提取出来形成一个抽象产品类,这些具体产品类都继承自这个抽象产品类。

(3)当需要增加一种产品的时候,需要做的是:增加一种继承自抽象产品的具体产品类,增加一种继承在抽象工厂的具体工厂类,更改客户端。而不需要在简单工厂模式中那样更改工厂内的switch。

工厂模式用于处理 如何获取实例对象问题,建造者模式用于处理如何建造实例对象 问题。
工厂方法的实现并不能减少工作量,但是它能够在必须处理新情况时,避免使已经很复杂的代码更加复杂

通常设计应该是从工厂方法开始,当设计者发现需要更大的灵活性时,设计便会向其他创建型模式演化。当设计者在设计标准之间进行权衡的时候,了解多个创建型模式可以给设计者更多的选择余地
(1)计算器的例子

#include <iostream>
#include <cstdlib>

using namespace std;

//抽象产品类
class Operation
{
protected:
    double numberA;
    double numberB;

public:
    double getA()
    {
        return numberA;
    }
    double getB()
    {
        return numberB;
    }
    void setA(double number)
    {
        numberA=number;
    }
    void setB(double number)
    {
        numberB=number;
    }

    virtual double GetResult()
    {
        double result=0;
        return result;
    }
};
//下面是四个具体产品类
class OperationAdd:public Operation
{
public:
    double GetResult()
    {
        double result=0;
        result=numberA+numberB;
        return result;
    }
};

class OperationSub:public Operation
{
public:
    double GetResult()
    {
        double result=0;
        result=numberA-numberB;
        return result;
    }
};

class OperationMul:public Operation
{
public:
    double GetResult()
    {
        double result=0;
        result=numberA*numberB;
        return result;
    }
};

class OperationDiv:public Operation
{
public:
    double GetResult()
    {
        double result=0;
        if(numberB!=0)
            result=numberA/numberB;
        return result;
    }
};

//抽象工厂类
class AbstractFactory
{
public:
    virtual Operation* createOperation()
    {
        return new Operation;
    }
};
//下面是四个具体工厂类,分别用于产生四个具体产品
class AddFactory:public AbstractFactory
{
public:
    Operation* createOperation()
    {
        Operation* oper=new OperationAdd;
        return oper;
    }
};

class SubFactory:public AbstractFactory
{
public:
    Operation* createOperation()
    {
        Operation* oper=new OperationSub;
        return oper;
    }
};

class MulFactory:public AbstractFactory
{
public:
    Operation* createOperation()
    {
        Operation* oper=new OperationMul;
        return oper;
    }
};

class DivFactory:public AbstractFactory
{
public:
    Operation* createOperation()
    {
        Operation* oper=new OperationDiv;
        return oper;
    }
};

//客户端
void main()
{
    AbstractFactory* af=NULL;
    af=new AddFactory();

    Operation* oper=NULL;
    oper=af->createOperation();

    oper->setA(1);
    oper->setB(2);
    cout<<oper->GetResult()<<endl;

    if(af!=NULL)
    {
        delete af;
        af=NULL;
    }
    if(oper!=NULL)
    {
        delete oper;
        oper=NULL;
    }

    system("pause");
}

(2)雷锋工厂

#include <iostream>
#include <cstdlib>

using namespace std;

//抽象产品类:雷锋
class Leifeng
{
public:
    virtual void Sweep()
    {
        cout<<"扫地"<<endl;
    }
    virtual void Wash()
    {
        cout<<"洗衣"<<endl;
    }
    virtual void BuyRice()
    {
        cout<<"买米"<<endl;
    }
};

//下面是两个具体产品类
class Undergraduate:public Leifeng
{
public:
    void Sweep()
    {
        cout<<"学生-扫地"<<endl;
    }
    void Wash()
    {
        cout<<"学生-洗衣"<<endl;
    }
    void BuyRice()
    {
        cout<<"学生-买米"<<endl;
    }
};

class Volunteer:public Leifeng
{
public:
    void Sweep()
    {
        cout<<"志愿者-扫地"<<endl;
    }
    void Wash()
    {
        cout<<"志愿者-洗衣"<<endl;
    }
    void BuyRice()
    {
        cout<<"志愿者-买米"<<endl;
    }
};

//抽象工厂类
class AbstractFactory
{
public:
    virtual Leifeng* CreateLeifeng()
    {
        return new Leifeng;
    }
};

//下面是两个具体工厂类,分别于两个具体产品相对应
class UndergraduateFactory:public AbstractFactory
{
public:
    Undergraduate* CreateLeifeng()
    {
        return new Undergraduate;
    }
};

class VolunteerFactory:public AbstractFactory
{
public:
    Volunteer* CreateLeifeng()
    {
        return new Volunteer();
    }
};

//客户端
void main()
{
    //想要生产Volunteer产品的话,只需要将此处的UndergraduateFactory更改为VolunteerFactory即可。
    AbstractFactory* af=NULL;
    af=new VolunteerFactory;

    Leifeng* lf=NULL;
    lf=af->CreateLeifeng();

    lf->BuyRice();
    lf->Sweep();
    lf->Wash();

    if(af!=NULL)
    {
        delete af;
        af=NULL;
    }
    if(lf!=NULL)
    {
        delete lf;
        lf=NULL;
    }

    system("pause");
}

这里写图片描述

3、抽象工厂模式:

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

好处:
1. 易于交换产品系列,例如Ifactory factory = new AccessFactory()在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。
2. 它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。
所有在用简单工厂的地方,都可以考虑用反射技术来去除switch或if,解除分支判断带来的耦合

缺点:如果要添加一个产品类,就得增加很多代码

包含的角色

(1)抽象工厂

(2)具体工厂:包括具体工厂1和具体工厂2。具体工厂1用于生产具体产品A1和具体产品B1,具体工厂2用于生产具体产品A2和具体产品B2;

(3)抽象产品:包括抽象产品A和抽象产品B;

(4)具体产品:包括抽象产品A所对应的具体产品A1和A2,以及抽象产品B所对应的具体产品B1和B2.

说明:在《大话设计模式》中,上述的1和2分别代表Sqlserver数据库和Access数据库。上述的A和B分别代表数据库中的User表和Department表。

优势

(1)抽象工厂模式是对工厂方法模式的改进。用于处理产品不只有一类的情况(工厂方法模式下,产品只有User这一类,而抽象工厂模式下,产品包括User和Department两类)。

(2)在以下情况下应当考虑使用抽象工厂模式:

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

在上例中,产品族包括两个:1和2,也就是Sqlserver数据库和Access数据库。每个产品族里面又包含两类产品:A和B,也就是User表和Department表。而每个产品族中的产品要一起使用,就是说产品族1中的两类产品A和B要一起使用,也就是说在SqlServer数据库中SqlServerUser表和SqlServerDepartment表要一起使用,Access数据库同理。
代码:

#include <iostream>
#include <cstdlib>

using namespace std;


//数据库表项:User
class User
{
private:
    int id;
    string name;
public:
    int getID()
    {
        return id;
    }
    string getName()
    {
        return name;
    }
    void setID(int ID)
    {
        this->id=ID;
    }
    void setName(string NAME)
    {
        this->name=NAME;
    }
};


//数据库表项:Department
class Department
{
private:
    int id;
    string name;
public:
    int getID()
    {
        return id;
    }
    string getName()
    {
        return name;
    }
    void setID(int ID)
    {
        this->id=ID;
    }
    void setName(string NAME)
    {
        this->name=NAME;
    }
};



//抽象产品A:IUser
class IUser
{
public:
    virtual void Insert(User user)=0;
    virtual User* GetUser(int id)=0;
};
//具体产品A1:SqlserverUser
class SqlserverUser:public IUser
{
public:
    void Insert(User user)
    {
        cout<<"在SQL Server中给User表增加了一条记录"<<endl;
    }
    User* GetUser(int id)
    {
        cout<<"在SQL Server中根据ID得到User表一条记录"<<endl;
        return NULL;
    }
};
//具体产品A2:AccessUser
class AccessUser:public IUser
{
public:
    void Insert(User user)
    {
        cout<<"在Access中给User表增加了一条记录"<<endl;
    }
    User* GetUser(int id)
    {
        cout<<"在Access中根据ID得到User表一条记录"<<endl;
        return NULL;
    }
};


//抽象产品B:IDepartment
class IDepartment
{
public:
    virtual void Insert(Department department)=0;
    virtual Department* GetDepartment(int id)=0;
};
//具体产品B1:SqlserverDepartment
class SqlserverDepartment:public IDepartment
{
public:
    void Insert(Department department)
    {
        cout<<"在Sql Server中给Department表添加了一条记录"<<endl;
    }
    Department* GetDepartment(int id)
    {
        cout<<"在SQL Server中根据ID得到Department表的一条记录"<<endl;
        return NULL;
    }
};
//具体产品B2:AccessDepartment
class AccessDepartment:public IDepartment
{
public:
    void Insert(Department department)
    {
        cout<<"在Access中给Department表添加了一条记录"<<endl;
    }
    Department* GetDepartment(int id)
    {
        cout<<"在Access中根据ID得到Department表的一条记录"<<endl;
        return NULL;
    }
};



//抽象工厂:IFactory
class IFactory
{
public:
    virtual IUser* CreateUser()=0;
    virtual IDepartment* CreateDepartment()=0;
};
//具体工厂1:SqlServerFactory
class SqlserverFactory:public IFactory
{
public:
    IUser* CreateUser()
    {
        return new SqlserverUser;
    }

    IDepartment* CreateDepartment()
    {
        return new SqlserverDepartment;
    }
};
//具体工厂2:AccessFactory
class AccessFactory:public IFactory
{
public:
    IUser* CreateUser()
    {
        return new AccessUser;
    }

    IDepartment* CreateDepartment()
    {
        return new AccessDepartment;
    }
};



//客户端
void  main()
{
    User user;
    Department department;

    //ConcreteFactory1
    IFactory* factory=NULL;
    factory=new SqlserverFactory;

    //ProductA1
    IUser* iu=NULL;
    iu=factory->CreateUser();
    iu->Insert(user);
    iu->GetUser(1);

    //ProductB1
    IDepartment* id=NULL;
    id=factory->CreateDepartment();
    id->Insert(department);
    id->GetDepartment(1);

    if(factory!=NULL)
    {
        delete factory;
        factory=NULL;
    }
    if(iu!=NULL)
    {
        delete iu;
        iu=NULL;
    }
    if(id!=NULL)
    {
        delete id;
        id=NULL;
    }

    system("pause");
}

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_34866146/article/details/81706070
今日推荐