大话设计模式C++版——抽象工厂模式
前面说过,简单工厂模式是最基础的一种设计模式,那以工厂命名的设计模式就是23种设计模式中最多的一种,他们一脉相承,一步一步进化而来,这里就是其中的最后一种——抽象工厂模式(Abstract Factory),其是在工厂方法模式的基础上改进而来,如果没有弄明白工厂方法模式的同学请先观看《大话设计模式C++版——工厂方法模式》。
为什么会有抽象工厂模式?抽象工厂模式是简单工厂模式缺陷的终极解决方式么?NO,抽象工厂模式并不是为了解决简单工厂模式的缺陷而活着,它是因为有新的使命而诞生。 一个简单的例子,有一个数据库保存着公司员工的信息,为了能够灵活使用各种数据库,将操作数据库的类抽象出来,并采用比简单工厂模式先进那么一点点的工厂方法模式实现。
1、工厂方法模式实现员工信息数据库操作
1.1 员工类和工厂类
typedef struct Employee
{
int nID;
TString tstrName;
}; class IEmployee
{
public:
virtual ~IEmployee() {} virtual bool InserttoDB(Employee& stEmployee) = 0;
virtual Employee GetEmployee(int nID) = 0;
}; class CEmployeefromMysql : public IEmployee
{
public:
bool InserttoDB(Employee& stEmployee)
{
_tprintf(_T("Insert employee %s into mysql\n"), stEmployee.tstrName.c_str());
return true;
} Employee GetEmployee(int nID)
{
Employee stEmployee;
printf("Get an employee from mysql by id %d\n", nID);
return stEmployee;
}
}; class CEmployeefromAccess : public IEmployee
{
public:
bool InserttoDB(Employee& stEmployee)
{
_tprintf(_T("Insert employee %s into access\n"), stEmployee.tstrName.c_str());
return true;
} Employee GetEmployee(int nID)
{
Employee stEmployee;
printf("Get an employee from access by id %d\n", nID);
return stEmployee;
}
}; class IFactory
{
public:
~IFactory() {} virtual IEmployee* CreateEmployee() = 0;
}; class CFactoryfromMysql : public IFactory
{
public:
IEmployee* CreateEmployee()
{
return new CEmployeefromMysql();
}
}; class CFactoryfromAccess : public IFactory
{
public:
IEmployee* CreateEmployee()
{
return new CEmployeefromAccess();
}
};
分别有 Mysql 和 Access 2种数据库的员工对象类和2种工厂对象类。
1.2 使用示例
void Test()
{
IFactory* poIFactory = new CFactoryfromMysql();
IEmployee* poIEmployee = NULL; if (!poIFactory)
{
return;
} poIEmployee = poIFactory->CreateEmployee(); if (poIEmployee)
{
Employee stEmployee; stEmployee.nID = 1;
stEmployee.tstrName = _T("Jim");
poIEmployee->InserttoDB(stEmployee);
delete poIEmployee;
} delete poIFactory;
}
注:TString定义如下
#ifdef UNICODE
#define TString std::wstring
#else
#define TString std::string
#endif
如果需要更换数据为 Access,只需要将“IFactory* poIFactory = new CFactoryfromMysql();”
改为“IFactory* poIFactory = new CFactoryfromAccess();”即可实现数据库的更换。
此时,问题来了。如果要在数据库增加一张表,用来存放公司部门信息,并对部门信息对象进行操作,部门对象也用员工对象定义类似的方法定义如下。
class IDepartment
{
public:
~IDepartment() {} virtual bool InserttoDB(Department& stDepartment) = 0;
virtual Department GetDepartment(int nID) = 0;
}; class CDepartmentfromMysql : public IDepartment
{
public:
bool InserttoDB(Department& stDepartment)
{
_tprintf(_T("Insert Department %s into mysql\n"), stDepartment.tstrDepartmentName.c_str());
return true;
} Department GetDepartment(int nID)
{
Department stDepartment;
printf("Get an Department from mysql by id %d\n", nID);
return stDepartment;
}
}; class CDepartmentfromAccess : public IDepartment
{
public:
bool InserttoDB(Department& stDepartment)
{
_tprintf(_T("Insert Department %s into access\n"), stDepartment.tstrDepartmentName.c_str());
return true;
} Department GetDepartment(int nID)
{
Department stDepartment;
printf("Get an Department from access by id %d\n", nID);
return stDepartment;
}
};
此时,如果仍使用工厂方法模式来处理,则可能会增加如下一行代码,来生产部门对象。
IDepartmentFactory* poIDepartmentFactoryFactory = new CDepartmentFactoryfromMysql();
如果采用的是简单工厂模式,由于要根据需要返回 IEmployee 和 IDepartment 2种对象,一个简单工厂已完全无法满足需求了,二个简单工厂(一个生产 IEmployee 对象,另一个生产 IDepartment 对象)则会发现一种数据库的操作都需要2个工厂类对象来处理,就像是想买苹果的手机需要找苹果公司去买,但买苹果的平板,却告知要到富士康公司去买了,已经失去简单工厂的本质意义了,也就是说简单工厂在此种情况下已经完全不能适应时代发展的需要了。工厂方法模式也有类似问题,如果需要更换数据库,需改更改2个工厂对象的用户代码,如果数据库中还要增加更多类型的信息操作,那么还需要增加更多的工厂对象,改动将越来越庞大。此时,该抽象工厂模式来拯救世界了,而且,实际上工厂方法模式早已为这一天准备了很久很久.....
2、抽象工厂模式拯救世界
2.1 抽象工厂模式的实现
class IFactory
{
public:
~IFactory() {} virtual IEmployee* CreateEmployee() = 0;
virtual IDepartment* CreateDepartment() = 0;
}; class CFactoryfromMysql : public IFactory
{
public:
IEmployee* CreateEmployee()
{
return new CEmployeefromMysql();
} IDepartment* CreateDepartment()
{
return new CDepartmentfromMysql();
}
}; class CFactoryfromAccess : public IFactory
{
public:
IEmployee* CreateEmployee()
{
return new CEmployeefromAccess();
} IDepartment* CreateDepartment()
{
return new CDepartmentfromAccess();
}
};
抽象工厂模式拯救世界的方式很简单,就是在抽象工厂早已准备好的工厂类接口 IFactory 中再小小的增加一个返回 IDepartment 部门对象的接口,然后所有的数据库工厂类中再实现生产 IDepartment 部门对象接口。
2.2 抽象工厂模式使用示例
void Test()
{
IFactory* poIFactory = new CFactoryfromMysql();
IEmployee* poIEmployee = NULL; if (!poIFactory)
{
return;
} poIEmployee = poIFactory->CreateEmployee(); if (poIEmployee)
{
Employee stEmployee; stEmployee.nID = 1;
stEmployee.tstrName = _T("Jim");
poIEmployee->InserttoDB(stEmployee);
delete poIEmployee;
} IDepartment* poIDepartment = poIFactory->CreateDepartment(); if (poIDepartment)
{
Department stDepartment; stDepartment.nID = 2;
stDepartment.tstrDepartmentName = _T("Marketing");
stDepartment.tstrManager = _T("Jim");
poIDepartment->InserttoDB(stDepartment);
delete poIDepartment;
}
delete poIFactory;
}
基本员工对象的部分不用变化,再增加部门对象的的代码即可,如果需要更换数据库,则只需要改动“IFactory*poIFactory = new CFactoryfromMysql();”一处即可。
抽象工厂模式解决了不论用户要买 iphone 还是要买 ipad,都只需要找苹果公司就可以了,如果要买小米或者小米平板,则统统找小米公司即可,工厂方法模式是一个工厂只生产一种产品,但当公司壮大升级为集团公司时,则一个公司可能会生产N种产品,那么此时需要抽象工厂模式来拯救公司的未来了。
世界安静片刻后,问题依然存在,尽管抽象工厂模式很牛X,但依然没有解决简单工厂模式和工厂方法模式遗留下来的问题——违背开放封闭原则,《大话设计模式》一书中最终给出了解决方案——采用反射,但反射这么高大上的东东在C++中是不存在的。C++是否真的就无法给出一个圆满的答案?是否最终拯救世界的重任还需C#来完成?欲知后事如何,请听下回分解。。。。。。
大话设计模式C++版——抽象工厂模式的更多相关文章
- 大话设计模式C++版——简单工厂模式
简单工厂模式应该是所有设计模式中最简单,也最基础的一种模式,以下是一个简单的采用工厂模式写一个加减法的计算器. 1.抽象接口类——依赖倒转原则(高层和底层都要依赖于抽象,针对接口编程) class I ...
- 大话设计模式Python实现- 抽象工厂模式
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的类 下面是一个抽象工厂的demo: #!/usr/bin/env pyth ...
- JAVA常用设计模式(一、抽象工厂模式)
抽象工厂模式 抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂.该超级工厂又称为其他工厂的工厂.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最 ...
- 设计模式学习心得<抽象工厂模式 Abstract Factory>
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂.该超级工厂又称为其他工厂的工厂.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 在抽 ...
- C#设计模式系列:抽象工厂模式(AbstractFactory)
出自:http://www.cnblogs.com/libingql/archive/2012/12/09/2809754.html 1. 抽象工厂模式简介 1.1 定义 抽象工厂(Abstract ...
- [Python编程实战] 第一章 python的创建型设计模式1.1抽象工厂模式
注:关乎对象的创建方式的设计模式就是“创建型设计模式”(creational design pattern) 1.1 抽象工厂模式 “抽象工厂模式”(Abstract Factory Pattern) ...
- IOS设计模式浅析之抽象工厂模式(Abstract Factory)
概述 在前面两章中,分别介绍了简单工厂模式和工厂方法模式,我们知道简单工厂模式的优点是去除了客户端与具体产品的依赖,缺点是违反了“开放-关闭原则”:工厂方法模式克服了简单工厂模式的缺点,将产品的创建工 ...
- 【java设计模式】-03抽象工厂模式
抽象工厂 简述 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类.在抽象工厂模式中,接口是负责创建一个相关对象的工厂 ...
- 一天一个设计模式——Abstract Factory抽象工厂模式
一.模式说明 前面学习了工厂方法(Factory Method)模式.在工厂方法模式中,在工厂方法模式中,父类决定如何生成实例,但并不决定所要生成的具体类,具体的处理交由子类来处理.这里学习的抽象工厂 ...
随机推荐
- Quartz.NET开源作业调度框架系列(五):AdoJobStore保存job到数据库
Quartz.NET 任务调度的核心元素是 scheduler, trigger 和 job,其中 trigger(用于定义调度时间的元素,即按照什么时间规则去执行任务) 和 job 是任务调度的元数 ...
- delphi 事件和属性的绑定
TWindowState = (wsNormal, wsMinimized, wsMaximized); TScrollingWinControl = class(TWinControl) priva ...
- JavaScript 数据类型判断
JavaScript 的数据类型分为两类:原始类型(基本类型)和对象类型(引用类型).原始类型包括数字.字符串和布尔值,另外有两个特殊的原始值:null 和 undefined,除此之外的都是对象.对 ...
- sharepoint2010问卷调查(1)-实现问卷的图片调查(采用JS实现)
1. 首先建立个图片库上传图片 2. 采用:评估范围(一系列选项或 Likert 范围)制作,如下图: http://win-i07fillcfom:8003/DocLib2/1.jpg http ...
- R语言学习
1.清屏 Ctrl + L 2.退出 q() 3.设置工作空间 getwd() setwd('D:\\Program Files\\RStudio\\workspace') 4.显档当前工作目录下的文 ...
- iOS启动过程
1.main函数 | 2.UIApplicationMain * 创建UIApplication对象 * 创建UIApplication的delegate对象 | 3.delega ...
- 安卓--shape简单使用
shape 先看下,系统自带的EditText和Button的外形 下面看加了shape后的效果 简单点讲,shape可以为组件加上背景边框,圆角之类的可以配合selector使用 shapeXXX. ...
- [Android]proguard重新编译和如何不混淆第三方jar包
转载自:http://glblong.blog.51cto.com/3058613/1536516 一.ant安装.环境变量配置及验证 (一)安装ant 到官方主页http://ant.apache. ...
- django 操作 下载 excel xls xlsx csv
网站开发离不开数据的导入导出,本文将介绍一下django如何操作excel 先安装 django-excel pip install django-excel 配置一下url url(r'^downl ...
- 体验最火的敏捷——SCRUM(厦门,2014.1.4)
1.概述SCRUM是当前最火的一种敏捷开发方法,有用户故事.冲刺.燃尽图等很多很酷的玩法,有牛B的产品负责人.SCRUM Master,有超强的自组织团队.本沙龙将为您展现当前最火最酷的敏捷开发方法! ...