【1】什么是抽象工厂模式?
原文:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
所有专业书上都是这句话:“为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。”
逐级分解一下:
1、为创建一组相关的对象提供一个接口,而且无需指定他们的具体类。
2、为创建一组相互依赖的对象提供一个接口,而且无需指定他们的具体类。
3、为创建对象提供一个接口,而且无需指定他们的具体类。
4、为创建对象提供一个接口。
5、一个接口。
抽象工厂:抽象是指接口,工厂是指集合,其实是接口集合。
既然是接口集合,那么属于哪种类型的接口集合?即具体工厂类。
比如SqlFactory,是指Sql数据库的接口集合。
而Sql数据库的接口集合最终都可以创建出哪种类型的Sql产品?即具体产品类。
比如SqlUser,SqlDepartment,是指具体的Sql产品类。
所以,抽象工厂,即创建出产品类的接口集合。
比如,IFactory,创建出产品类的接口集合,不可以实例化对象,仅仅提供接口规范。
每个具体工厂,即创建出同一类产品的功能集合。
比如,SqlFactory,创建出同一类产品SqlUser、SqlDepartment的功能集合。
【2】抽象工厂模式的逻辑结构图及代码示例:
逻辑结构图:
代码示例:
1 #include2 #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 #include2 #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.
顺序 选择 循环 总结