抽象方法模式:提供一个创建一系列相关或互相依赖对象的接口,而无需指定他们具体的类。
三种模式的对比:
简单工厂模式 | 工厂模式 | 抽象工厂模式 | |
产品 | 可以有多个但是都属于同一类,
同一等级。都继承产品抽象类。 |
可以有多个但是都属于同一类,同一等级。
都继承产品抽象类。 |
可以有不同种类的产品,每类有多中
具体产品; |
抽象产品 | 只能有一个 | 只能有一个; | 多个抽象产品类;每个抽象产品类可
以派生多种具体产品; |
抽象工厂类 | 只能有一个,可以派生出多个具体工厂类; | 只有一个,可派生出多个具体工厂类; | |
具体工厂 | 制造不同的产品,直接实例化
产品对象; |
一个具体工厂类只能创建一个具体的产品; | 可以创建多个具体产品类的实例; |
以书上的数据库访问为例:
抽象工厂中的角色有:
(1)抽象工厂:只能一个(IFactory)
(2)具体工厂: 包括具体工厂1:SqlServerFactory和具体工厂2:AccessFactory。
具体工厂1用于生产具体产品A1:SqlserverUser和具体产品B1:SqlserverDepartment,
具体工厂2用于生产具体产品A2:AccessUser和B2;AccessDepartment,
(3)抽象产品: 包括抽象产品A:IUser和抽象产品B:IDepartment;
(4)具体产品:包括抽象产品A所对应的具体产品A1和A2,以及抽象产品B所对应的具体产品B1和B2.
优点:
(1)抽象工厂模式是对工厂方法模式的改进,可以处理多类的产品,不局限与某一类,因为有多个抽象产品类。例如此例如果在工厂方法模式下,产品只有User或者Department其中的一类,而抽象工厂模式下,产品包括User和Department两类)
(2)易于交换产品系列,例如我们在选择数据库时,只需要初始化一次AccessFactory或者SqlServerFactory,就可以使用不同数据库的配置,使之使用非常灵活。另外它使创建实例的过程与客户端分离。很好的符合了开放-封闭原则和依赖倒转原则。
缺点:如果要增加一个新的功能,需要改动的地方太多。
例如如果我们要增加一个新的项目表Project,那么我的增加至少三个类:IProject,SqlserverProject、AccessProject,还需要更改抽象类IFactory、SqlserverFactory和AccessFactory才可以实现,这是非常多的。
其UML图如下:
具体实现代码如下:
#include <iostream> using namespace std; //数据库表项:User class User { private: int id; string name; public: int getID() { return id; } string getName() { return name; } void setID(int ID) { this->id=ID; } void setName(string NAME) { this->name=NAME; } }; //数据库表项:Department class Department { private: int id; string name; public: int getID() { return id; } string getName() { return name; } void setID(int ID) { this->id=ID; } void setName(string NAME) { this->name=NAME; } }; //抽象产品A:IUser class IUser { public: virtual void Insert(User user)=0; virtual User* GetUser(int id)=0; }; //具体产品A1:SqlserverUser class SqlserverUser:public IUser { public: void Insert(User user) { cout<<"在SQL Server中给User表增加了一条记录"<<endl; } User* GetUser(int id) { cout<<"在SQL Server中根据ID得到User表一条记录"<<endl; return NULL; } }; //具体产品A2:AccessUser class AccessUser:public IUser { public: void Insert(User user) { cout<<"在Access中给User表增加了一条记录"<<endl; } User* GetUser(int id) { cout<<"在Access中根据ID得到User表一条记录"<<endl; return NULL; } }; //抽象产品B:IDepartment class IDepartment { public: virtual void Insert(Department department)=0; virtual Department* GetDepartment(int id)=0; }; //具体产品B1:SqlserverDepartment class SqlserverDepartment:public IDepartment { public: void Insert(Department department) { cout<<"在Sql Server中给Department表添加了一条记录"<<endl; } Department* GetDepartment(int id) { cout<<"在SQL Server中根据ID得到Department表的一条记录"<<endl; return NULL; } }; //具体产品B2:AccessDepartment class AccessDepartment:public IDepartment { public: void Insert(Department department) { cout<<"在Access中给Department表添加了一条记录"<<endl; } Department* GetDepartment(int id) { cout<<"在Access中根据ID得到Department表的一条记录"<<endl; return NULL; } }; //抽象工厂:IFactory class IFactory { public: virtual IUser* CreateUser()=0; virtual IDepartment* CreateDepartment()=0; }; //具体工厂1:SqlServerFactory class SqlserverFactory:public IFactory { public: IUser* CreateUser() { return new SqlserverUser; } IDepartment* CreateDepartment() { return new SqlserverDepartment; } }; //具体工厂2:AccessFactory class AccessFactory:public IFactory { public: IUser* CreateUser() { return new AccessUser; } IDepartment* CreateDepartment() { return new AccessDepartment; } }; //客户端 int main() { User user; Department department; //ConcreteFactory1 IFactory* factory=NULL; factory=new SqlserverFactory; //ProductA1 IUser* iu=NULL; iu=factory->CreateUser(); iu->Insert(user); iu->GetUser(1); //ProductB1 IDepartment* id=NULL; id=factory->CreateDepartment(); id->Insert(department); id->GetDepartment(1); if(factory!=NULL) { delete factory; factory=NULL; } if(iu!=NULL) { delete iu; iu=NULL; } if(id!=NULL) { delete id; id=NULL; } system("pause"); return 0; }
运行结果:
小结:如果产品单一,要想达到以上的效果,合适用工厂模式;但是如果有多个品种分级时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。可以根据实际情况进行选择。