伟创力(世界500强企业),公司有笔记本生产车间、电视机车间、空调车间、电话生产等车间,各生产车间各行其责,生产出不同类型的产品。伟创力不再是生产单一产品的企业,而是生产出多种不同类型的产品,各产品属于不同产品等级结构中。在设计模式中,也存在一种类似的模式,可以创建一系列产品,这些产品位于不同产品等级结构,产品之间可以没有任何联系,但他们组合起来,可以成为一个产品族,称之为抽象工厂模式。
1、产品等级结构与产品族
在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法具有唯一性。但是有时候我们希望一个工厂可以提供多个产品对象,而不是单一的产品对象,如一个电器工厂,它可以生产电视机、电冰箱、空调等多种电器,而不是只生产某一种电器。为了更好地理解抽象工厂模式,我们先引入两个概念:
(1) 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、TCL电视机,创维电视机。则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
产品等级结构图
(2) 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱。海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中,海尔电视机、海尔电冰箱构成了一个产品族
产品族图
当系统所提供的工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式。抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形式。抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、更有效率。
2、BeyondCompare的设计与实现
BeyondCompare是一款代码比较软件,能够比较不同版本的代码之间的差异,类似SVN版本控制器。例如:在版本1基础之上进行修改升级为版本2,BeycongComapare能够对版本1和2代码进行比较,检测出哪些地方存在差异。需求:设计一款类似BeyondCompare的软件,能够在Windows平台和Linux平台下对Cpp格式和Java格式的源代码进行比较,检测出差异。
使用简单工厂模式的实现方式
代码格式类型图
格式工厂图
要在Windows和Linux平台下都能针对Cpp和Java代码格式文件进行比较,考虑到扩展性,可以定义一个抽象CPP类,Windows平台下的Cpp格式和Linux平台下的Cpp格式都继承于这个抽象Cpp类。 同时定义一个抽象Java类,Windows平台下的Java格式和Linux平台下的Java格式都继承于这个抽象Java类
代码格式类型实现如下:
#ifndef _PRODUCT_H_
#define _PRODUCT_H_
#include <iostream>
#include <string>
using namespace std;
//抽象Cpp代码格式类
class CppCodeStyle
{
public:
//虚函数,用于显示处理的代码格式
virtual void DisplayCodeStyle() = 0;
};
//Windows Cpp代码格式
class WindowsCppCodeStyle : public CppCodeStyle
{
public:
void DisplayCodeStyle()
{
cout << "我对Windows Cpp文件进行代码比较" << endl;
}
};
//Linux Cpp代码格式
class LinuxCppCodeStyle : public CppCodeStyle
{
public:
void DisplayCodeStyle()
{
cout << "我对Linux Cpp文件进行代码比较" << endl;
}
};
/*********************************************************/
/*********************************************************/
//抽象Java代码格式
class JavaCodeStyle
{
public:
//虚函数,用于显示处理的代码格式
virtual void DisplayCodeStyle() = 0;
};
//Windows Java代码格式
class WindowsJavaCodeStyle : public JavaCodeStyle
{
public:
void DisplayCodeStyle()
{
cout << "我对Windows Java文件进行代码比较" << endl;
}
};
//Linux Java代码格式
class LinuxJavaCodeStyle : public JavaCodeStyle
{
public:
void DisplayCodeStyle()
{
cout << "我对Linux Java文件进行代码比较" << endl;
}
};
#endif
Cpp格式和Java格式是两种不同类型的产品,因此可以提供两个简单工厂,一个工厂用于创建不同平台下的Cpp格式对象,另一个工厂用于创建不同平台下的Java格式对象。
格式工厂实现代码如下:
#ifndef _PRODUCT_FACTORY_H_
#define _PRODUCT_FACTORY_H_
#include "Product.h"
//Cpp格式工厂
class CppProductFactory
{
public:
//创建具体平台的Cpp,strCppType表示windows还是linux下的cpp
static CppCodeStyle * CreateCpp(string strCppType)
{
CppCodeStyle * pCppCodeStyle = NULL;
if( 0 == strcmp(strCppType.c_str(), "Windows Cpp") )
{
pCppCodeStyle = new WindowsCppCodeStyle();
}
else if( 0 == strcmp(strCppType.c_str(), "Linux Cpp") )
{
pCppCodeStyle = new LinuxCppCodeStyle();
}
else
{
return NULL;
}
return pCppCodeStyle;
}
};
//Java格式工厂
class JavaProductFactory
{
public:
//创建具体平台的Java,strJavaType表示windows还是linux下的Java
static JavaCodeStyle * CreateJava(string strJavaType)
{
JavaCodeStyle * pJavaCodeStyle = NULL;
if( 0 == strcmp(strJavaType.c_str(), "Windows Java") )
{
pJavaCodeStyle = new WindowsJavaCodeStyle();
}
else if( 0 == strcmp(strJavaType.c_str(), "Linux Java") )
{
pJavaCodeStyle = new LinuxJavaCodeStyle();
}
else
{
return NULL;
}
return pJavaCodeStyle;
}
};
#endif
CppProductFactory产品工厂用于创建windows平台和Linux平台下的Cpp格式对象,JavaProductFactory产品工厂用于创建windows平台和Linux平台下的Java格式对象。
测试文件实现代码如下:
#include <iostream>
using namespace std;
#include "Product.h"
#include "ProductFactory.h"
int main()
{
/*************创建Windows Cpp *************************************/
CppCodeStyle * pWindowsCppCodeStyle = CppProductFactory::CreateCpp("Windows Cpp");
pWindowsCppCodeStyle->DisplayCodeStyle();
/*************创建Linux Java *************************************/
JavaCodeStyle * pLinuxJavaCodeStyle = JavaProductFactory::CreateJava("Linux Java");
pLinuxJavaCodeStyle->DisplayCodeStyle();
/*************销毁操作********************************************/
delete pWindowsCppCodeStyle;
pWindowsCppCodeStyle = NULL;
delete pLinuxJavaCodeStyle;
pLinuxJavaCodeStyle = NULL;
return 0;
}
编译并执行,结果如下: