前面我们介绍过了简单工厂,如果我们还想提供更高一层的抽象,或者在业务需要时,我们需要为每一个简单的工厂提供一个抽象,那我们可以使用抽象工厂。而抽象工厂,也仅仅是对简单工厂的进一步抽象。这也在一定程度上说明了,面向对象编程的能力,其实就是抽象事物的能力。
下面举个简单的示例进行说明(自己动手敲一下,感觉绝对不同):
#pragma once
#include <string>
#pragma warning (disable:4996)
//用户类
class User
{
public:
void getfield(int id, char* name)
{
m_id = id;
strcpy(m_name, name);
}
private:
int m_id;
char m_name[32];
};
//抽象用户表
class Iuser
{
public:
virtual void Insert(User user){ }
virtual User* getuser(int id){ return nullptr;}
private:
};
//Mysql用户表
class MySqluser:public Iuser
{
public:
void Insert(User user)
{
printf("Mysql插入一个user\n");
}
User* getuser(int id)
{
printf("Mysql获取一个user\n");
return nullptr;
}
private:
};
//Sqlite用户表
class Sqliteuser :public Iuser
{
public:
void Insert(User user)
{
printf("Sqlite插入一个user\n");
}
User* getuser(int id)
{
printf("Sqlite获取一个user\n");
return nullptr;
}
private:
};
//抽象工厂
class IFactory
{
public:
IFactory():m_iuser(nullptr){}
virtual Iuser* createuser(){ return m_iuser; }
virtual ~IFactory()
{
if (m_iuser!=nullptr)
delete m_iuser;
}
/*IDepartment* createdepartment(){ }*/
protected:
Iuser * m_iuser;
};
class MysqlFactory:public IFactory
{
public:
Iuser* createuser()override
{
m_iuser = new MySqluser;
return m_iuser;
}
/*IDepartment createdepartment(){ }*/
};
class SqliteFactory :public IFactory
{
public:
Iuser* createuser()override
{
m_iuser = new Sqliteuser;
return m_iuser;
}
/*IDepartment createdepartment(){ }*/
};
int main()
{
User user; //实例化一个User对象
user.getfield(123, "tester");
IFactory * factory = new MysqlFactory;
Iuser * iu = factory->createuser();
iu->Insert(user);
iu->getuser(1);
delete factory;
return 0;
}
抽象工厂,优点在于使用一个具体的工厂十分容易。只需要改变具体的工厂,就可以使用不同的产品配置,比如上面的不同数据库工厂。使得具体实例的创建过程和客户端分离。
抽象工厂当然也有缺点,比如一旦发生改动,将会有大量改动。比如增加一个Department类,抽象工厂以及具体的两个工厂,都要修改。所以使用该模式,尽量使用自动化生成,避免大量手工重复劳动。