抽象工厂
通过对象创建模式,绕开 new,来避免对象创建(new)过程中导致的紧耦合(new 需要依赖具体类),从而支持对象创建的稳定,它是抽象接口后的第一步工作
动机
主要是解决一系列”相互依赖的对象“,工厂方法是解决”单个对象“,即多个 Factory 组成一个总的基类。
定义
提供一个接口,让该接口创建一系列”相关或者相互依赖的对象“,无需指定它们的具体类。
示例代码
class EmployeeDAO {
public:
vector<Employee> GetEmployees() {
SqlConnection* connection = new SqlConnection();
connection->ConnectionString = "...";
SqlCommand* command = new SqlCommand();
command->CommandText = "@@@";
command->SetConnection(connection);
SqlDataReader* reader = command->ExecuteReader();
while(reader->Read()) {
// ...
}
}
};
假设我们现在有一个 EmployeeDAO 可以获取访问数据库,然后获取员工的一些信息,这里连接数据库的过程就是 Sqlxxx 相关类之间相互依赖,并且这里都是依赖了具体的类,之后如果需求有变化,例如使用其他数据库,这个类就不适用了。那么了解过工厂模式的可以知道,现在我们想实现变化,需要加一层,新的抽象来创建具体的类,这里需要为每一个 new 过的类创建一个工厂基类。
// connection 工厂基类
class ConnectionFactory {
public:
virtual Connection* CreateConnection() = 0;
virtual ~ConnectionFactory(){}
};
// connection 工厂具体类
class SqlConnectionFactory : public ConnectionFactory {
public:
virtual Connection* (){ return new SqlConnection(); }
}
// connection 工厂具体类
class OracleConnectionFactory : public ConnectionFactory {
public:
virtual Connection* (){ return new OracleConnection(); }
}
// command 工厂基类
class CommandFactory {
public:
virtual Command* CreateCommand() = 0;
virtual ~CommandFactory(){}
};
// command 工厂具体类
class SqlCommandFactory : public CommandFactory {
public:
virtual Command* (){ return new SqlCommand(); }
}
// command 工厂具体类
class OracleCommandFactory : public CommandFactory {
public:
virtual Command* (){ return new OracleCommand(); }
}
// dataReader 工厂基类
class DataReaderFactory {
public:
virtual DataReader* CreateDataReader() = 0;
virtual ~DataReaderFactory(){}
};
// dataReader 工厂具体类
class SqlDataReaderFactory : public DataReaderFactory {
public:
virtual DataReader* (){ return new SqlDataReader(); }
}
// dataReader 工厂具体类
class OracleDataReaderFactory : public DataReaderFactory {
public:
virtual DataReader* (){ return new OracleDataReader(); }
}
class EmployeeDAO {
ConnectionFactory* connectionFactory; // 多态
CommandFactory* commandFactory;
DataReaderFactory* dataReaderFactory;
public:
// 这里省略了EmployeeDAO 初始化成员变量的构造函数
vector<Employee> GetEmployees() {
Connection* connection = connectionFactory->CreateConnection();
connection->ConnectionString = "...";
Command* command = commandFactory->CreateCommand();
command->CommandText = "@@@";
command->SetConnection(connection); // 关联性
DataReader* reader = command->ExecuteReader(); // 关联性
while(reader->Read()) {
// ...
}
}
};
上面的实现采用工厂模式的思路,确实解决了创建对象依赖具体类导致程序脆弱的问题,但是现在还有一个问题就是,数据库之间的操作需要保持一致性,当前 3 个独立的抽象工厂作为参数传入 EmployeeDAO 类,但是现在的结构并不能保证它们是一致的,完全可以出现传入了 Sql 的 connection,却传入了 oracle 的 command,这样肯定会报错的。因此Abstract Factory 抽象工厂的模式会更近一步,将相关之间有关联性的工厂基类都放在一起。
class IDBFactory {
public:
virtual Connection* CreateConnection() = 0;
virtual Command* CreateCommand() = 0;
virtual DataReader* CreateDataReader() = 0;
virtual ~IDBFactory(){}
};
class IDBSqlFactory : public IDBFactory{
public:
virtual Connection* () { return new SqlConnection(); }
virtual Command* () { return new SqlCommand(); }
virtual DataReader* () { return new SqlDataReader(); }
};
class IDBOracleFactory : public IDBFactory{
public:
virtual Connection* () { return new OracleConnection(); }
virtual Command* () { return new OracleCommand(); }
virtual DataReader* () { return new OracleDataReader(); }
};
class EmployeeDAO {
IDBFactory* idbFactory;
public:
vector<Employee> GetEmployees() {
Connection* connection = idbFactory->CreateConnection();
connection->ConnectionString = "...";
Command* command = idbFactory->CreateCommand();
command->CommandText = "@@@";
command->SetConnection(connection); // 关联性
DataReader* reader = command->ExecuteReader(); // 关联性
while(reader->Read()) {
// ...
}
}
};
至此,上面就完成了 Abstract Factory 抽象工厂模式,其中将相互关联的工厂接口合并在一起,实现了高内聚,多态实现了松耦合。
结构图
总结
- 如果没有应对”多系列对象构建“的需求变化,则没有必要使用 Abstract Factory 模式,简单工厂就足够了。
- ”系列对象“是指某一特定系列下的对象之间有相互依赖或者作用关系,不同系列的对象之间不能相互依赖(sql 的 command 不能依赖 oracle 的 connection)
- Abstract Factory 主要用于应对”新系列“的需求变动,缺点在于难以应对”新对象“的需求变动(在 connection,command,datareader 的基础上增加功能接口),抽象基类的要求就是要稳定。
其他设计模式汇总:
[设计模式] —— 设计模式的介绍及分类