C++ 设计模式 抽象工厂模式

以下内容均来自GeekBand极客班C++ 设计模式课程(李建忠老师主讲)

Abstract Factory

“对象创建”模型

通过“对象创建”模式绕开new,避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。

典型模式

Factory Method

Abstract Factory

Prototype

Builder

动机(Motivation)

和工厂方法非常类似,都是解决同一类问题

在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。

《设计模式》GOF的定义:

提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。

AbstractFactory代表:IDBFactory

ConcreteFactory1 & ConcreteFactory2 代表:SqlFactory & OraclFactory 

AbstractProductA代表:IDBConnection

AbstractProductB代表:IDBCommand

AbstractProductC代表:IDBDataReader

示例

假设有这么一个类,一个数据访问层,现在假设我们访问的是Sql数据库,代码示例如下:

class EmployeeDAO{
public:
    vector<EmployeeDAO> GetEmployees(){
        SqlConnection * connection = 
                new SqlConnection();
        connection->ConnectionString("...");
        
        SqlCommand * command = 
                new SqlCommand();
        command->SetConnection(connection);//二者之间存在联系
        command->CommandText("...");
        
        SqlDataReader * reader = command->ExecuteReader();
        while(reader->Read()){
            
        }
    }
};

但是如果在可见的未来,我们要访问其他类的数据库,显然GetEmployees函数就依赖了太多具体的内容。

我们先丰满一下示例的其他部分:

//数据库访问有关的基类
class IDBConnection{

};

class IDBCommand{

};

class IDBDataReader{

};

支持SQL Server

//支持SQL Server
class SqlConnection : public IDBConnection{

};

class SqlCommand : public IDBCommand{

};

class SqlDataReader : public IDBDataReader{

};

支持 Oracle

//支持 Oracle
class OracleConnection : public IDBConnection{

};

class OracleCommand : public IDBCommand{

};

class OracleDataReader : public IDBDataReader{

};

我们已经有了抽象类,就可以对EmployeeDAO进行重构了

class EmployeeDAO{
public:
    vector<EmployeeDAO> GetEmployees(){
        IDBConnection * connection = 
                new SqlConnection();
        connection->ConnectionString("...");
        
        IDBCommand * command = 
                new SqlCommand();
        command->CommandText("...");
        
        IDBDataReader * reader = command->ExecuteReader();
        while(reader->Read()){
            
        }
    }
};

但是我们发现还是不够的,new还是有问题的,需要将new也去掉才行

如果依旧使用工厂模式:

class IDBConnection{

};
class IDBConnectionFactory{
public:
    virtual IDBConnection * CreateDBConnection() = 0;
    virtual ~IDBConnectionFactory(){}
};


class IDBCommand{

};
class IDBCommandFactory{
public:
    virtual IDBCommand * CreateDBConnection() = 0;
    virtual ~IDBCommandFactory(){}
};

class IDBDataReader{

};
class IDBDataReaderFactory{
public:
    virtual IDBDataReader * CreateDBConnection() = 0;
    virtual ~IDBDataReaderFactory(){}
};

以上是抽象类,下面是具体实现类

//支持SQL Server
class SqlConnection : public IDBConnection{

};
class SqlConnectionFactory : public IDBConnectionFactory{

};

class SqlCommand : public IDBCommand{

};
class SqlCommandFactory : public IDBCommandFactory{

};

class SqlDataReader : public IDBDataReader{

};
class SqlDataReaderFactory : public IDBDataReaderFactory{

};

之后我们对Employee进行修改:

class EmployeeDAO{
    IDBConnectionFactory * _ConnectionFactory;
    IDBCommandFactory * _CommandFactory;
    IDBDataReaderFactory * _DataReaderFactory;
public:
    vector<EmployeeDAO> GetEmployees(){
        IDBConnection * connection = _ConnectionFactory->CreateDBConnection();

        connection->ConnectionString = "...";

        IDBCommand * command = _CommandFactory->CreateDBCommand();
        command->SetConnection(connection);//二者之间存在联系
        command->CommandText = "...";

        IDBDataReader * reader = _DataReaderFactory->CreateDBDataReader();
        while(reader->Read()){

        }
    }
};

这个问题目前来看是解决了

但是因为IDBConnection和IDBCommand之间存在联系,不能 IDBConnection指向的是SQL Server但是IDBCommand指向的是Oracle

    IDBConnectionFactory * _ConnectionFactory;
    IDBCommandFactory * _CommandFactory;
    IDBDataReaderFactory * _DataReaderFactory;

三个对象必须是同一个系列的。

我们需要对其进行整合,将三个工厂放在一起

//数据库访问有关的基类

class IDBConnection{

};
class IDBCommand{

};
class IDBDataReader{

};

class IDBFactory{
public:
    virtual IDBConnection * CreateDBConnection() = 0;
    virtual IDBCommand * CreateDBCommand() = 0;
    virtual IDBDataReader * CreateDBDataReader() = 0;
    virtual ~IDBFactory(){}
};

那么具体的实现,以SQL Server为例:

//支持SQL Server
class SqlConnection : public IDBConnection{

};
class SqlCommand : public IDBCommand{

};
class SqlDataReader : public IDBDataReader{

};
class SqlFactory : public IDBFactory{
public:
    virtual IDBConnection * CreateDBConnection(){
        return new SqlConnection();
    }
    virtual IDBCommand * CreateDBCommand(){
        return new SqlCommand();
    }
    virtual IDBDataReader * CreateDBDataReader(){
        return new SqlDataReader();
    }
    virtual ~SqlFactory(){}
};

此处也体现了高聚合的编程思想:相同的内容,将其放在一起

class EmployeeDAO{
    IDBFactory * _Factory;
public:
    vector<EmployeeDAO> GetEmployees(){
        IDBConnection * connection = _Factory->CreateDBConnection();

        connection->ConnectionString = "...";

        IDBCommand * command = _Factory->CreateDBCommand();
        command->SetConnection(connection);//二者之间存在联系
        command->CommandText = "...";

        IDBDataReader * reader = _Factory->CreateDBDataReader();
        while(reader->Read()){

        }
    }
};

要点总结

如果没有应对“多系类对象构建”的需求变化,则没有必要使用Avstract Factory模式,这时候使用简单的工厂完全可以。

“系类对象”指的是在某一特定系类下的对象之间有相互依赖,或作用的关系。不同系统的对象之间不能相互依赖。

Abstract Factory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值