博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
抽象工厂模式
阅读量:5836 次
发布时间:2019-06-18

本文共 7426 字,大约阅读时间需要 24 分钟。

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

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

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

逐级分解一下:

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

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

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

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

5、一个接口。

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

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

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

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

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

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

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

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

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

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

逻辑结构图:

代码示例:

1 #include 
2 #include
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 IFactory101 {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中返回user154 在Access中设置user155 在Access中返回Department156 在Access中设置Department157 请按任意键继续. . .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 
2 #include
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中返回user144 在sql中设置user145 在sql中返回Department146 在sql中设置Department147 请按任意键继续. . .148 */

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

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

 

Good Good Study, Day Day Up.

顺序 选择 循环 总结

转载地址:http://xeccx.baihongyu.com/

你可能感兴趣的文章
Spring boot 使用WebAsyncTask处理异步任务
查看>>
js 数组清空 方法 汇总
查看>>
nginx https 配置样例
查看>>
最课程阶段大作业06:U度节能平台控制系统
查看>>
MongoDB:通过mongodump【时间一致性】备份,快速创建secondary复制集节点——更精简的方式2...
查看>>
配置 influxDB 鉴权及 HTTP API 写数据的方法
查看>>
手把手教你使用 VuePress 搭建个人博客
查看>>
spring事务配置的两种方式
查看>>
关于Oracle 10.2.0.5 版本应用SCN补丁14121009相关问题
查看>>
lbs@node
查看>>
NIO的介绍及使用(总结)
查看>>
Java面试试题
查看>>
hibernate-mapping的各种属性配置
查看>>
(轉貼) 如何在Ubuntu安裝VMWare Tools? (OS) (Linux) (Ubuntu) (VMWare)
查看>>
需求:如何做好深度访谈
查看>>
精通CSS高级Web标准解决方案:相对定位与绝对定位
查看>>
错排公式的推导
查看>>
浅谈C和C++中的const关键字
查看>>
S3C2410 bootloader ----VIVI阅读笔记 (转)下
查看>>
什么是9.png
查看>>