网站换网址了怎么找,建设一个网站需要多少钱,厦门软件园多客宝网站开发,做文字图片的网站抽象工厂与工厂方法极其类似#xff0c;都是绕开new的#xff0c;但是有些许不同。
动机
在软件系统中#xff0c;经常面临着“一系列相互依赖的对象”的创建工作#xff1b;同时#xff0c;由于需求的变化#xff0c;往往存在更多系列对象的创建工作。
假设案例
假设…抽象工厂与工厂方法极其类似都是绕开new的但是有些许不同。
动机
在软件系统中经常面临着“一系列相互依赖的对象”的创建工作同时由于需求的变化往往存在更多系列对象的创建工作。
假设案例
假设现在有这样一个需求我们需要做一个数据访问层。 在数据访问层需要创建一系列的对象比如建立链接创建数据库的命令对象创建数据库的DataReader对象。但是数据库可能不只有Sql的可能还有别的类型的。
class EmployeeDAO{public:vectorEmployeeDO GetEmployees(){// sql 链接SqlConnection* connection new SqlConnection();// 链接字符串connection-ConnectionString ...;// sql 命令SqlCommand* command new SqlCommand();command-CommandText...;// 设置链接command-SetConnection(connection);// 执行读取SqlDataReader* reader command-ExecuteReader();while (reader-Read()){}}
};
当前代码实现是 紧耦合 EmployeeDAO 类与具体的数据库实现如 SQL Server紧密耦合难以切换到其他数据库如 MySQL、Oracle 等。 //数据库访问有关的基类
class IDBConnection{};// IDB 连接工厂
class IDBConnectionFactory{
public:virtual IDBConnection* CreateDBConnection()0;
};// IDB 命令基类
class IDBCommand{};
// IDB 命令工厂
class IDBCommandFactory{
public:virtual IDBCommand* CreateDBCommand()0;
};// IData 数据阅读器
class IDataReader{};// IData 数据阅读器工厂
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:vectorEmployeeDO GetEmployees(){// 多态实现IDBConnection* connection dbConnectionFactory-CreateDBConnection();connection-ConnectionString(...);IDBCommand* command dbCommandFactory-CreateDBCommand();command-CommandText(...);command-SetConnection(connection); //关联性IDBDataReader* reader command-ExecuteReader(); //关联性while (reader-Read()){}}
};
按照之前的工厂模式编写代码
//数据库访问有关的基类
class IDBConnection {};// IDB 连接工厂
class IDBConnectionFactory {
public:virtual IDBConnection* CreateDBConnection() 0;
};// IDB 命令基类
class IDBCommand {};
// IDB 命令工厂
class IDBCommandFactory {
public:virtual IDBCommand* CreateDBCommand() 0;
};// IData 数据阅读器
class IDataReader {};// IData 数据阅读器工厂
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:vectorEmployeeDO GetEmployees() {// 多态实现IDBConnection* connection dbConnectionFactory-CreateDBConnection();connection-ConnectionString(...);IDBCommand* command dbCommandFactory-CreateDBCommand();command-CommandText(...);command-SetConnection(connection); //关联性IDBDataReader* reader command-ExecuteReader(); //关联性while (reader-Read()) {}}
};上述方法确实能够解决new的问题但是也存在一些其它的问题。就是一开始创建的三个工厂必须是同系列的具备关联性。解决这个问题就需要引入抽象工厂。
首先定义数据库操作的抽象接口:
// 数据库连接接口
class IDbConnection {
public:virtual void SetConnectionString(const std::string connStr) 0;virtual void Open() 0;virtual void Close() 0;virtual ~IDbConnection() {}
};// 数据库命令接口
class IDbCommand {
public:virtual void SetCommandText(const std::string commandText) 0;virtual void SetConnection(IDbConnection* connection) 0;virtual IDbDataReader* ExecuteReader() 0;virtual ~IDbCommand() {}
};// 数据读取器接口
class IDbDataReader {
public:virtual bool Read() 0;virtual std::string GetString(int index) 0;virtual int GetInt(int index) 0;virtual ~IDbDataReader() {}
};
为每种数据库实现具体的类。例如SQL Server 的实现
// SQL Server 连接
class SqlConnection : public IDbConnection {
public:void SetConnectionString(const std::string connStr) override {// 设置连接字符串}void Open() override {// 打开连接}void Close() override {// 关闭连接}
};// SQL Server 命令
class SqlCommand : public IDbCommand {
private:std::string commandText;IDbConnection* connection;
public:void SetCommandText(const std::string commandText) override {this-commandText commandText;}void SetConnection(IDbConnection* connection) override {this-connection connection;}IDbDataReader* ExecuteReader() override {// 执行命令并返回读取器return new SqlDataReader();}
};// SQL Server 数据读取器
class SqlDataReader : public IDbDataReader {
public:bool Read() override {// 读取下一行return true;}std::string GetString(int index) override {// 获取字符串数据return data;}int GetInt(int index) override {// 获取整数数据return 123;}
};定义一个抽象工厂接口用于创建数据库相关的对象:
class IDbFactory {
public:virtual IDbConnection* CreateConnection() 0;virtual IDbCommand* CreateCommand() 0;virtual IDbDataReader* CreateDataReader() 0;virtual ~IDbFactory() {}
};为每种数据库实现具体的工厂类。例如SQL Server 的工厂
class SqlDbFactory : public IDbFactory {
public:IDbConnection* CreateConnection() override {return new SqlConnection();}IDbCommand* CreateCommand() override {return new SqlCommand();}IDbDataReader* CreateDataReader() override {return new SqlDataReader();}
};将 EmployeeDAO 类改为依赖抽象工厂而不是具体的数据库实现
class EmployeeDAO {
private:IDbFactory* dbFactory;
public:EmployeeDAO(IDbFactory* factory) : dbFactory(factory) {}std::vectorEmployeeDO GetEmployees() {std::vectorEmployeeDO employees;// 创建连接IDbConnection* connection dbFactory-CreateConnection();connection-SetConnectionString(...);connection-Open();// 创建命令IDbCommand* command dbFactory-CreateCommand();command-SetCommandText(SELECT * FROM Employees);command-SetConnection(connection);// 执行命令并读取数据IDbDataReader* reader command-ExecuteReader();while (reader-Read()) {EmployeeDO employee;employee.name reader-GetString(0);employee.age reader-GetInt(1);employees.push_back(employee);}// 释放资源delete reader;delete command;delete connection;return employees;}
};使用示例,在客户端代码中通过工厂创建 EmployeeDAO 对象
int main() {// 创建 SQL Server 工厂IDbFactory* sqlFactory new SqlDbFactory();// 创建 EmployeeDAO 对象EmployeeDAO dao(sqlFactory);// 获取员工数据std::vectorEmployeeDO employees dao.GetEmployees();// 释放工厂delete sqlFactory;return 0;
}改进后的优点
解耦EmployeeDAO 类不再依赖具体的数据库实现而是依赖抽象接口符合依赖倒置原则。扩展性如果需要支持新的数据库类型只需实现新的工厂类和数据库类无需修改 EmployeeDAO 类。可测试性可以通过模拟工厂和数据库对象轻松进行单元测试。符合开闭原则系统对扩展开放对修改关闭。模式定义
提供一个接口让该接口负责创建一系列“相关或者相互依赖的对象”无需指定它们具体的类。
要点总结 如果没有应对“多系列对象构建”的需求变化则没有必要使用Abstract Factory模式这时候使用简单的工厂完全可以。 “系列对象”指的是在某一特定系列下的对象之间有相互依赖、或作用的关系。不同系列的对象之间不能相互依赖。 Abstract Factory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。因为如果要加新对象的话就会改变抽象基类IDBFactory