设计模式之抽象工厂

简单介绍

抽象工厂就是提供一个创建一系列相关或者相互依赖对象的接口,具体就是下面的表示,假如数据库有两个表user和department两个表的有相同的操作,比如有insert和get,接口一样但是操作所需要的数据,和所访问的表不一样,而且还可能这两个表会在不同的数据库中存储,比如access和sqlserver,因此我们把不同的表作为基类,根据不同的数据库来派生出不同的派生类,这样就可以隐藏不同数据库的操作细节差异,只需知道表的操作接口即可,然后实现一个工厂类,首先有一个工厂基类作为抽象,根据不同的数据库类型派生出不同的工厂类,每一个工厂类进生产特定数据库的表(这里假设两个表在同一种数据库中)。和工厂模式的区别,工厂模式只能创建一个类,抽象工厂可以创建一系列相关的类。

代码案例

下面实现了抽象工厂模式,这里有两个表 user、department,还可能有两种不同的数据库access、sqlserver,因此使用抽象工厂模式,具体详情看下述代码。

这个设计模式有以下一个部分:

  1. 不同的表基类,对应iUser、iDepartment
    1. 相同的表不同的数据库派生类,对应sqlserverUser、accessUser、sqlserverDepartment、accessDepartment
  2. 工厂基类,对应iFactory
    1. 不同数据库的派生类,对应accessFactory、sqlFactory
#include 
using namespace std;


class user
{
    public:
        int id;
        string name;
};
class iUser
{
    public:
        virtual void insert(user *use) = 0;
        virtual user *getUser(int id) = 0;
};
class sqlserverUser : public iUser
{
    public:
        virtual void insert(user *use)
        {
            cout<<"在SQL server 中给user表添加一条记录\n";
        }
        virtual user * getUser(int id)
        {
            cout<<"在SQL server 中根据id在user表得到一条记录\n";
            return nullptr;
        }
};
class accessUser : public iUser
{
    public:
        virtual void insert(user *use)
        {
            cout<<"在Access 中给user表添加一条记录\n";
        }
        virtual user * getUser(int id)
        {
            cout<<"Access 中根据id给user表得到一条记录\n";
            return nullptr;
        }
};

class iDepartment
{
    public:
        virtual void insert(string department) = 0;
        virtual string getDepartment(int fd) = 0;
};
class sqlserverDepartment : public iDepartment
{
    public:
        virtual void insert(string department)
        {
            cout<<"在SQL server中给department表中添加了一条记录\n";
        }
        virtual string getDepartment(int fd)
        {
            cout<<"在SQL server中根据department得到一条department表的记录\n";
            return "";
        }
};

class accessDepartment : public iDepartment
{
    public:
        virtual void insert(string department)
        {
            cout<<"在Access中给department表中添加了一条记录\n";
        }
        virtual string getDepartment(int fd)
        {
            cout<<"在Access中根据id得到一条department表的记录\n";
            return "";
        }
};

class iFactory
{
    public:
        virtual iUser *creatUser() = 0;
        virtual iDepartment *creatDepartment() = 0;
};
class sqlserverFactory : public iFactory
{
    virtual iUser *creatUser(){return new sqlserverUser();};
    virtual iDepartment *creatDepartment(){return new sqlserverDepartment();};
};
class accessFactory : public iFactory
{
    virtual iUser *creatUser(){return new accessUser();};
    virtual iDepartment *creatDepartment(){return new accessDepartment();};
};

int main()
{
    user *use = new user();
    use->id = 1;
    use->name = "wqwq";
    string dept = "";
    iFactory *factory = new accessFactory();
    iUser *iu = factory->creatUser();
    iu->insert(use);
    iu->getUser(1);

    iDepartment *id = factory->creatDepartment();
    id->insert(dept);
    id->getDepartment(1);

    delete use;
    delete factory;
    delete iu;
    delete id;
    return 0;
}

优点:

可以创建一系列相关的类,自己就不需要考虑这些类之间的关系,直接由抽象工厂来帮创建即可,若是适应工厂模式,那么根据不同的表和不同的数据库,会有很多种组合,这样的话就会把不同数据库这一细节暴露给了用户,违反了最小知道原则。

当需要更改不用的数据库类型的时候,只需要把工厂类的具体类更换为不同的派生类即可,其他类不需要修改,客户端可以直接使用抽象表的接口,具体的类名不会暴露给客户端

缺点:

当需要新添加表的时候需要增加很多类(还好了,对添加开放,对修改封闭),并且需要更改抽象工厂类(因为抽象工厂要生成一系列的类,那么添加新表的时候,需要改抽象工厂类)

优化:

由于派生的工厂类就是创建对应数据库的表对象,因此可以使用简单工厂模式来创建,根据参数生成不同的对象。java中有反射这个东西。

符合的原则

1、迪米特原则(最小知道原则)

这个应该可以能看出,用户仅知道表的接口,内部的数据库类型完全不知情。

2、单一职责

每个工厂类仅负责一种数据库的表的创建,概不负责其他类型数据库,一个表类仅复杂一个表的操作,概不负责其他表的操作。

你可能感兴趣的:(设计模式)