本系列所有文章来自李建忠老师的设计模式笔记,系列如下: 设计模式(一)面向对象设计原则 23种设计模式(二)组件协作之模板方法 23种设计模式(三)组件协作之策略模式 23种设计模式(四)组件协作之观察者模式 23种设计模式(五)单一职责之装饰模式 23种设计模式(六)单一职责之桥模式 23种设计模式(七)对象创建之工厂方法 23种设计模式(八)对象创建之抽象工厂 23种设计模式(九)对象创建之原型模式 23种设计模式(十)对象创建之构建器 23种设计模式(十一)对象性能之单件模式 23种设计模式(十二)对象性能之享元模式 23种设计模式(十三)接口隔离之门面模式 23种设计模式(十四)接口隔离之代理模式 23种设计模式(十五)接口隔离之适配器 23种设计模式(十六)接口隔离之中介者 23种设计模式(十七)状态变化之状态模式 23种设计模式(十八)状态变化之备忘录 23种设计模式(十九)数据结构之组合模式 23种设计模式(二十)数据结构之迭代器 23种设计模式(二十一)数据结构之职责链 23种设计模式(二十二)行为变化之命令模式 23种设计模式(二十三)行为变化之访问器 23种设计模式(二十四)领域规则之解析器
抽象工厂与工厂方法极其类似,都是绕开new的,但是有些许不同。
在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。
假设现在有这样一个需求,我们需要做一个数据访问层。
在数据访问层需要创建一系列的对象,比如建立链接,创建数据库的命令对象,创建数据库的DataReader对象。但是数据库可能不只有Sql的,可能还有别的类型的。
EmployeeDAO1.cpp class EmployeeDAO{ public: vector<EmployeeDO> GetEmployees(){ SqlConnection* connection = new SqlConnection(); connection->ConnectionString = "..."; SqlCommand* command = new SqlCommand(); command->CommandText="..."; command->SetConnection(connection); SqlDataReader* reader = command->ExecuteReader(); while (reader->Read()){ } } };那么上述这种实现就不支持多种数据库的方法。
如果要支持多种数据库,第一种反应就是实现面向接口的编程。基于上一节的工厂方法,为每一个类实现一个工厂
EmployeeDAO2.cpp //数据库访问有关的基类 class IDBConnection{ }; class IDBConnectionFactory{ public: virtual IDBConnection* CreateDBConnection()=0; }; class IDBCommand{ }; class IDBCommandFactory{ public: virtual IDBCommand* CreateDBCommand()=0; }; class IDataReader{ }; class IDataReaderFactory{ public: virtual IDataReader* CreateDataReader()=0; }; //支持SQL Server class SqlConnection: public IDBConnection{ }; class SqlConnectionFactory:public IDBConnectionFactory{ }; class SqlCommand: public IDBCommand{ }; class SqlCommandFactory:public IDBCommandFactory{ }; class SqlDataReader: public IDataReader{ }; class SqlDataReaderFactory:public IDataReaderFactory{ }; //支持Oracle class OracleConnection: public IDBConnection{ }; class OracleCommand: public IDBCommand{ }; class OracleDataReader: public IDataReader{ }; class EmployeeDAO{ // 三个工厂创建三个对象 IDBConnectionFactory* dbConnectionFactory; IDBCommandFactory* dbCommandFactory; IDataReaderFactory* dataReaderFactory; public: vector<EmployeeDO> GetEmployees(){ // 多态实现 IDBConnection* connection = dbConnectionFactory->CreateDBConnection(); connection->ConnectionString("..."); IDBCommand* command = dbCommandFactory->CreateDBCommand(); command->CommandText("..."); command->SetConnection(connection); //关联性 IDBDataReader* reader = command->ExecuteReader(); //关联性 while (reader->Read()){ } } };上述方法确实能够解决new的问题,但是也存在一些其它的问题。就是一开始创建的三个工厂必须是同系列的,具备关联性。解决这个问题就需要引入抽象工厂。
如果将一开始创建的三个工厂放在一个类里面,就不会存在这个问题。
如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合?
EmployeeDAO3.cpp //数据库访问有关的基类 class IDBConnection{ }; class IDBCommand{ }; class IDataReader{ }; class IDBFactory{ public: virtual IDBConnection* CreateDBConnection()=0; virtual IDBCommand* CreateDBCommand()=0; virtual IDataReader* CreateDataReader()=0; }; //支持SQL Server class SqlConnection: public IDBConnection{ }; class SqlCommand: public IDBCommand{ }; class SqlDataReader: public IDataReader{ }; class SqlDBFactory:public IDBFactory{ public: virtual IDBConnection* CreateDBConnection()=0; virtual IDBCommand* CreateDBCommand()=0; virtual IDataReader* CreateDataReader()=0; }; //支持Oracle class OracleConnection: public IDBConnection{ }; class OracleCommand: public IDBCommand{ }; class OracleDataReader: public IDataReader{ }; class EmployeeDAO{ IDBFactory* dbFactory; public: vector<EmployeeDO> GetEmployees(){ IDBConnection* connection = dbFactory->CreateDBConnection(); connection->ConnectionString("..."); IDBCommand* command = dbFactory->CreateDBCommand(); command->CommandText("..."); command->SetConnection(connection); //关联性 IDBDataReader* reader = command->ExecuteReader(); //关联性 while (reader->Read()){ } } };提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。
如果没有应对“多系列对象构建”的需求变化,则没有必要使用Abstract Factory模式,这时候使用简单的工厂完全可以。
“系列对象”指的是在某一特定系列下的对象之间有相互依赖、或作用的关系。不同系列的对象之间不能相互依赖。
Abstract Factory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。(因为如果要加新对象的话,就会改变抽象基类IDBFactory)