大话设计模式C++版——抽象工厂模式

前面说过,简单工厂模式是最基础的一种设计模式,那以工厂命名的设计模式就是23种设计模式中最多的一种,他们一脉相承,一步一步进化而来,这里就是其中的最后一种——抽象工厂模式(Abstract Factory),其是在工厂方法模式的基础上改进而来,如果没有弄明白工厂方法模式的同学请先观看《大话设计模式C++版——工厂方法模式》。

为什么会有抽象工厂模式?抽象工厂模式是简单工厂模式缺陷的终极解决方式么?NO,抽象工厂模式并不是为了解决简单工厂模式的缺陷而活着,它是因为有新的使命而诞生。 一个简单的例子,有一个数据库保存着公司员工的信息,为了能够灵活使用各种数据库,将操作数据库的类抽象出来,并采用比简单工厂模式先进那么一点点的工厂方法模式实现。

1、工厂方法模式实现员工信息数据库操作

1.1 员工类和工厂类

typedef	struct Employee
{
	int		nID;
	TString	tstrName;
};

class IEmployee
{
public:
	~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();”即可实现数据库的更换。

此时,问题来了。如果要在数据库增加一张表,用来存放公司部门信息,并对部门信息对象进行操作,部门对象也用员工对象定义类似的方法定义如下。

typedef	struct Department
{
	int		nID;
	TString	tstrDepartmentName;
	TString	tstrManager;
};

class IDepartment
{
public:
	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#来完成?欲知后事如何,请听下回分解。。。。。。

时间: 2024-12-25 06:45:53

大话设计模式C++版——抽象工厂模式的相关文章

大话设计模式C++版——简单工厂模式

简单工厂模式应该是所有设计模式中最简单,也最基础的一种模式,以下是一个简单的采用工厂模式写一个加减法的计算器. 1.抽象接口类--依赖倒转原则(高层和底层都要依赖于抽象,针对接口编程) class IOperation { public: IOperation() : m_nNuml(0), m_nNumr(0) {} virtual ~IOperation() {} virtual void SetNum(int nNuml = 0, int nNumr = 0) { m_nNuml = nN

设计模式学习03—抽象工厂模式

1.动机与定义 工厂模式中,一个工厂仅仅能提供一个或一类产品,当产品种类较多,形成产品系列(比方我们要创建跨平台的button,菜单,文本框等等一系列GUI控件: 单纯使用工厂模式会产生大量工厂,并且后期维护也不方便,我们能够从产品中找到规律,假设产品等级相对固定,以后仅仅会新增产品族,那么我们就能够把整个产品族放到一个工厂创建,以后新增其它系统产品族也很方便,例如以下图: 这样的模式就是抽象工厂,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则须要面对多个产品等级结构,一个工厂等级结构能

设计模式C++实现——抽象工厂模式

模式定义: 抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类. 抽象工厂允许客户使用抽象的接口来创建一组相关产品,而不需要知道实际产出的具体产品时什么.这样一来,客户就从具体的产品中被解耦了. 模式结构: 举例: 数据库访问程序设计,不同的数据库访问方式可能不一样,为了抽象对对不同数据库的访问,可以将数据库隐藏起来,提供统一的访问方式,用多态进行实现. UML设计: 编程实现及执行结果: #include <iostream> using namespace st

设计模式学习-抽象工厂模式

1.定义 提供接口,创建一系列相关或独立的对象,而不指定这些对象的具体类. 2.类图 3.代码示例 1 package com.zhaoyangwoo.abstractfactory; 2 3 /** 4 * Created by john on 16/5/2. 5 * @author wuzhaoyang 6 * <p> 7 * 抽象工厂:多个抽象产品类,派生出多个具体产品类:一个抽象工厂类,派生出多个具体工厂类:每个具体工厂类可创建多个具体产品类的实例. 8 * 即提供一个创建一系列相关或

[Python编程实战] 第一章 python的创建型设计模式1.1抽象工厂模式

注:关乎对象的创建方式的设计模式就是"创建型设计模式"(creational design pattern) 1.1 抽象工厂模式 "抽象工厂模式"(Abstract Factory Pattern)用来创建复杂的对象,这种对象由许多小对象组成,而这些小对象都属于某个特定的"系列"(family). 比如说,在GUI 系统里可以设计"抽象控件工厂"(abstract widget factory),并设计三个"具体子

23种设计模式[3]:抽象工厂模式

一.简单工厂模式(静态工厂方法,不属于23种GOF设计模式之一) 定义:定义一个用于创建产品对象的方法,由该工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例. 类型:创建类模式 public interface SmsService { void sendSms(); } public class MontnetsService implements SmsService { @Override public void sendSms() { Syste

JAVA常用设计模式(一、抽象工厂模式)

抽象工厂模式 抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂.该超级工厂又称为其他工厂的工厂.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类.每个生成的工厂都能按照工厂模式提供对象. 意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 主要解决:主要解决接口选择的问题. 何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一

一天一个设计模式——Abstract Factory抽象工厂模式

一.模式说明 前面学习了工厂方法(Factory Method)模式.在工厂方法模式中,在工厂方法模式中,父类决定如何生成实例,但并不决定所要生成的具体类,具体的处理交由子类来处理.这里学习的抽象工厂方法模式中,抽象工厂使用抽象的零件组装成抽象的产品.即使用包含特定的方法接口零件,将零件组装成抽象产品. 二.模式类图: 上面的类图中包含两个包:包含抽象工厂,抽象零件,抽象产品的类所在的包以及具体工厂实现类的包. 三.代码示例 1.Item类: package com.designpattern.

[设计模式] javascript 之 抽象工厂模式

抽象工厂模式说明 1. 工厂方法模式的问题: 在工厂方法模式里,创建类都需要通过 工厂类,如果要扩展程序,就必须修改工厂类,这违背了闭包原则,对扩展开放,对修改关闭:对于设计有一定的问题. 2. 如何解决:就要用到抽象工厂模式,就是对功能类单独创建工厂类,这样就不必修改之前的代码,又扩展了功能. 3. 工厂模式其实就是对 实现同一接口的 实现类 的 统一 工厂方式创建调用,但 javascript 没有接口这号东西,所以就去掉这一层 实现,但位功能类的成员及方法都应当一样; 抽象工厂源码例子 1