抽象工厂模式

【1】什么是抽象工厂模式?

原文:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。

所有专业书上都是这句话:“为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。”

逐级分解一下:

1、为创建一组相关的对象提供一个接口,而且无需指定他们的具体类。

2、为创建一组相互依赖的对象提供一个接口,而且无需指定他们的具体类。

3、为创建对象提供一个接口,而且无需指定他们的具体类。

4、为创建对象提供一个接口。

5、一个接口。

抽象工厂:抽象是指接口,工厂是指集合,其实是接口集合。

既然是接口集合,那么属于哪种类型的接口集合?即具体工厂类。

比如SqlFactory,是指Sql数据库的接口集合。

而Sql数据库的接口集合最终都可以创建出哪种类型的Sql产品?即具体产品类。

比如SqlUser,SqlDepartment,是指具体的Sql产品类。

所以,抽象工厂,即创建出产品类的接口集合。

比如,IFactory,创建出产品类的接口集合,不可以实例化对象,仅仅提供接口规范。

每个具体工厂,即创建出同一类产品的功能集合。

比如,SqlFactory,创建出同一类产品SqlUser、SqlDepartment的功能集合。

【2】抽象工厂模式的逻辑结构图及代码示例:

逻辑结构图:

代码示例:

  1 #include <string>
  2 #include <iostream>
  3 using namespace std;
  4 
  5 // 抽象产品类1
  6 class IUser
  7 {
  8 public:
  9     virtual void getUser() = 0;
 10     virtual void setUser() = 0;
 11 };
 12 
 13 // 具体产品类1(SqlUser)
 14 class SqlUser : public IUser
 15 {
 16 public:
 17     void getUser()
 18     {
 19         cout << "在sql中返回user" << endl;
 20     }
 21     void setUser()
 22     {
 23         cout << "在sql中设置user" << endl;
 24     }
 25 };
 26 
 27 // 具体产品类1(AccessUser)
 28 class AccessUser : public IUser
 29 {
 30 public:
 31     void getUser()
 32     {
 33         cout << "在Access中返回user" << endl;
 34     }
 35     void setUser()
 36     {
 37         cout << "在Access中设置user" << endl;
 38     }
 39 };
 40 
 41 // 抽象产品类2
 42 class IDepartment
 43 {
 44 public:
 45     virtual void getDepartment() = 0;
 46     virtual void setDepartment() = 0;
 47 };
 48 
 49 // 具体产品类2(SqlDepartment)
 50 class SqlDepartment : public IDepartment
 51 {
 52 public:
 53     void getDepartment()
 54     {
 55         cout << "在sql中返回Department" << endl;
 56     }
 57     void setDepartment()
 58     {
 59         cout << "在sql中设置Department" << endl;
 60     }
 61 };
 62 
 63 // 具体产品类2(AccessDepartment)
 64 class AccessDepartment : public IDepartment
 65 {
 66 public:
 67     void getDepartment()
 68     {
 69         cout << "在Access中返回Department" << endl;
 70     }
 71     void setDepartment()
 72     {
 73         cout << "在Access中设置Department" << endl;
 74     }
 75 };
 76 
 77 // 抽象工厂类
 78 class IFactory
 79 {
 80 public:
 81     virtual IUser *createUser() = 0;
 82     virtual IDepartment *createDepartment() = 0;
 83 };
 84 
 85 // 具体工厂类(SqlFactory)
 86 class SqlFactory : public IFactory
 87 {
 88 public:
 89     IUser *createUser() 
 90     {
 91         return new SqlUser(); // 创建具体产品1(SqlUser)
 92     }
 93     IDepartment *createDepartment() 
 94     {
 95         return new SqlDepartment(); // 创建具体产品2(SqlDepartment)
 96     }
 97 };
 98 
 99 // 具体工厂类(AccessFactory)
100 class AccessFactory : public IFactory
101 {
102 public:
103     IUser *createUser()
104     {
105         return new AccessUser(); // 创建具体产品1(AccessUser)
106     }
107     IDepartment *createDepartment() 
108     {
109         return new AccessDepartment(); // 创建具体产品2(AccessDepartment)
110     }
111 };
112 
113 void main()
114 {
115     IFactory *pFactory = NULL;
116     IUser *pUser = NULL;
117     IDepartment *pDepartment = NULL;
118 
119     pFactory = new AccessFactory();
120     if (NULL == pFactory)
121     {
122         return;
123     }
124 
125     pUser = pFactory->createUser();
126     if (NULL == pUser)
127     {
128         return;
129     }
130     pDepartment = pFactory->createDepartment();
131     if (NULL == pDepartment)
132     {
133         return;
134     }
135 
136     pUser->getUser();
137     pUser->setUser();
138     pDepartment->getDepartment();
139     pDepartment->setDepartment();
140     
141     delete pFactory;
142     pFactory = NULL;
143     delete pUser;
144     pUser = NULL;
145     delete pDepartment;
146     pDepartment = NULL;
147 
148     system("pause");
149 }
150 
151 // run out:
152 /*
153 在Access中返回user
154 在Access中设置user
155 在Access中返回Department
156 在Access中设置Department
157 请按任意键继续. . .
158 */

抽象产品类、抽象工厂类、具体产品类、具体工厂类如上注释。

【3】抽象工厂模式结构图

结构图如下所示:

为了加深宏观的理解,特搜了这张图贴上。

【4】工厂方法模式与抽象工厂模式的区别

详细对比请参见下图:

抽象工厂模式更难理解,需要用心琢磨,仔细体会。

【5】抽象工厂模式的优点和缺点

抽象工厂模式的优点:

1、便于交换产品系。

由于具体工厂类,例如IFactory factory = new SqlFactory(),在一个应用中只需要在初始化时出现一次。

这就使得改变一个应用的具体工厂变得很简单,而想要使用不同的产品配置只需要改变具体工厂即可。

2、客户端与具体创建实例过程分离。

客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。

抽象工厂模式的缺点(程序也是很有原则性的,比如:开放-封闭原则):

针对第一点优点,试想第一点(封闭原则,对于修改尽量关闭):客户端程序显然不可能只有一处使用IUser或IDepartment。

而如此设计,如果有100处调用了数据库访问类呢?是不是就需要更改100次IFactory factory = new AccessFactory()这样的代码才行?

很明显,不能满足我们想改动一处就完全达到要求的目的。

第二点(开放原则,对于扩展尽量开放):仅仅能很方便的切换数据库访问代码是很有局限性的,假设用户的需求改变需要增加功能,比如增加项目表Project。

先明确一下需要改动的地方。至少增加三个类,IProject、SqlserverProject、AccessProject,还需要更改IFactory、SqlserverFactory、AccessFactory才可以完全满足要求。

以上俩个缺点,又让我们陷入深深的沉思。

【6】改进方案1:简单工厂改进抽象工厂

代码示例如下:

  1 #include <string>
  2 #include <iostream>
  3 using namespace std;
  4 
  5 // 抽象产品类1
  6 class IUser
  7 {
  8 public:
  9     virtual void getUser() = 0;
 10     virtual void setUser() = 0;
 11 };
 12 
 13 // 具体产品类1(SqlUser)
 14 class SqlUser : public IUser
 15 {
 16 public:
 17     void getUser()
 18     {
 19         cout << "在sql中返回user" << endl;
 20     }
 21     void setUser()
 22     {
 23         cout << "在sql中设置user" << endl;
 24     }
 25 };
 26 
 27 // 具体产品类1(AccessUser)
 28 class AccessUser : public IUser
 29 {
 30 public:
 31     void getUser()
 32     {
 33         cout << "在Access中返回user" << endl;
 34     }
 35     void setUser()
 36     {
 37         cout << "在Access中设置user" << endl;
 38     }
 39 };
 40 
 41 // 抽象产品类2
 42 class IDepartment
 43 {
 44 public:
 45     virtual void getDepartment() = 0;
 46     virtual void setDepartment() = 0;
 47 };
 48 
 49 // 具体产品类2(SqlDepartment)
 50 class SqlDepartment : public IDepartment
 51 {
 52 public:
 53     void getDepartment()
 54     {
 55         cout << "在sql中返回Department" << endl;
 56     }
 57     void setDepartment()
 58     {
 59         cout << "在sql中设置Department" << endl;
 60     }
 61 };
 62 
 63 // 具体产品类2(AccessDepartment)
 64 class AccessDepartment : public IDepartment
 65 {
 66 public:
 67     void getDepartment()
 68     {
 69         cout << "在Access中返回Department" << endl;
 70     }
 71     void setDepartment()
 72     {
 73         cout << "在Access中设置Department" << endl;
 74     }
 75 };
 76 
 77 // 工厂方法类
 78 class DataAccess
 79 {
 80 private:
 81     static string db;
 82 
 83 public:
 84     static IUser *createUser()
 85     {
 86         if (db == "sql")
 87         {
 88             return new SqlUser();
 89         }
 90         else if (db == "access")
 91         {
 92             return new AccessUser();
 93         }
 94 
 95         return NULL;
 96     }
 97 
 98     static IDepartment *createDepartment()
 99     {
100         if (db == "sql")
101         {
102             return new SqlDepartment();
103         }
104         else if (db == "access")
105         {
106             return new AccessDepartment();
107         }
108 
109         return NULL;
110     }
111 };
112 
113 string DataAccess::db = "sql";
114 
115 void main()
116 {
117     IUser *pUser = NULL;
118     IDepartment *pDepartment = NULL;
119 
120     pUser = DataAccess::createUser();
121     if (NULL == pUser)
122         return;
123 
124     pDepartment = DataAccess::createDepartment();
125     if (NULL == pDepartment)
126         return;
127 
128     pUser->getUser();
129     pUser->setUser();
130     pDepartment->getDepartment();
131     pDepartment->setDepartment();
132 
133     delete pUser;
134     pUser = NULL;
135     delete pDepartment;
136     pDepartment = NULL;
137 
138     system("pause");
139 }
140 
141 // run out:
142 /*
143 在sql中返回user
144 在sql中设置user
145 在sql中返回Department
146 在sql中设置Department
147 请按任意键继续. . .
148 */

利用DataAccess(数据访问)类替换掉了IFactory、SqlserverFactory、AccessFactory三个工厂类。

【7】改进方案2:配置文件 + 抽象工厂模式

 

Good Good Study, Day Day Up.

顺序 选择 循环 总结

posted @ 2014-08-30 20:19  kaizenly  阅读(482)  评论(0编辑  收藏  举报
打赏