设计模式9——抽象工厂

动机

  在软件设计中经常面对一系列相互依赖的对象的创建工作,由于需求变化,经常面对更多对象的创建工作。

1. 引入问题

代码如下:

class EmployeeDB
{
public:
	vector<EmployeeInfo> GetEmployee()
	{
		/* 创建SQL对象,建立初始网络连接 */
		SqlConnect *connection = new SqlConnection();
		connection->ConnectNet("ip:192.168.0.1");
		/* 创建command对象 */
		SqlCommand *command = new SqlCommand();
		command->Command("SELECT * FROM TENNER");
		
		/* 相互依赖的对象:命令需要 连接对象对其传输 */
		command->SetConnection(connection);
	}
};

  先不考虑抽象工厂的问题,为了文章具有通读性,先对其解决第一个问题:

  • 上面函数中是写了SqlServer的数据库操作过程,如果后面要兼容MySQL或者Oracle呢?

2. 第一部优化

 兼容各种数据库

/* 数据库操作的两个基类 */
class DBConnection
{
public:
	virtual DBConnection()=0;
};
class DBCommand
{
public:
	virtual DBCommand()=0;
};

下面是一种数据库,另外种类的类似,就不列出来了.

/* SqlServer数据库 */
class SqlDBConnection : public DBConnection
{
public:
	virtual DBConnection(){}//仍可保留虚函数
};
class SqlDBCommand : public DBCommand
{
public:
	virtual DBCommnd(){}
};

这时上面的函数就可以这样使用:

vector<EmployeeInfo> GetEmployee()
	{
		//SqlConnect *connection = new SqlConnection();
		DBConnect *connection = new SqlConnection();
		connection->ConnectNet("ip:192.168.0.1");
		//SqlCommand *command = new SqlCommand();
		DBCommand *command = new SqlCommand();
		command->Command("SELECT * FROM TENNER");
		
		command->SetConnection(connection);
	}

  这样我们发现所作的优化好像并没有什么,还存在问题,创建了具体的对象,严重耦合.

3. 使用工厂优化

首先创建连个工厂的基类,声明构建对象的纯虚函数:

class DBConnectFactory
{
public:
	virtual DBConnection *DBConnectObjCreate() = 0; 
};
class DBCommandFactory
{
public:
	virtual DBCommand *DBCommandObjFactory() = 0; 
};

针对一种数据库,构建自己的工厂

class SqlConnectFactory : public DBConnectFactory
{
public:
	virtual DBConnection *DBConnectObjCreate()
	{
		return new SqlDBConnection();
	}
};
class SqlCommandFactory : public DBCommandFactory
{
public:
	virtual DBCommand *DBCommandObjCreate()
	{
		return new SqlDBCommand();
	}
};

此时,我们最开始的函数就可以这样写

class EmployeeDB
{
public:
	DBConnectFactory *dbConnectFact;
	DBCommandFactory *dbCmdFact;
public:
	vector<EmployeeInfo> GetEmployee()
	{
		DBConnect *connection = new SqlConnection();
						修改  = dbConnectFact->DBConnectObjCreate();
		connection->ConnectNet("ip:192.168.0.1");
	
		DBCommand *command = new SqlCommand();
					修改   = dbCmdFact->DBCommandObjCreate();
		command->Command("SELECT * FROM TENNER");
		
		command->SetConnection(connection);
	}
}

还存在问题吗?答案为是。
为什么,因为有两个工厂,如果传进来的两个工厂的子类对象不是同一个数据库类型,就无法兼容。
比如传进来的是Oracle的Connect工厂,但却是MySql的Command工厂,问题是显而易见的。

4. 继续优化

  从工厂入手,也很简单,把工厂合为一个,只是合并。

class DBOptFactory
{
public:
	virtual DBConnection *DBConnectObjCreate() = 0; 
	virtual DBCommand *DBCommandObjFactory() = 0; 
};

这里实现具体工厂也需要合并:

class SqlConnectFactory : public DBConnectFactory
{
public:
	virtual DBConnection *DBConnectObjCreate()
	{
		return new SqlDBConnection();
	}
	virtual DBCommand *DBCommandObjCreate()
	{
		return new SqlDBCommand();
	}
};

如此以来,最终的代码如下:

```cpp
class EmployeeDB
{
public:
	DBOptFactory *dbOptFact;
public:
	vector<EmployeeInfo> GetEmployee()
	{
		DBConnect *connection = new SqlConnection();
						修改  = dbOptFact->DBConnectObjCreate();
		connection->ConnectNet("ip:192.168.0.1");
	
		DBCommand *command = new SqlCommand();
					修改   = dbOptFact->DBCommandObjCreate();
		command->Command("SELECT * FROM TENNER");
		
		command->SetConnection(connection);
	}
}

 这是什么,这相当于嵌套了两层的多态。
来到这里,就需要解释一下,抽象工厂中的抽象是什么含义:
  多态就是要实现抽象,抽象工厂就是一种不止生产一种具体类型对象的工厂,各种对象都可以生产。所以说名为组合工厂更合适.

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值