工厂设计模式
1、定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。 ——《设计模式》GoF
2、代码实现
代码背景:实现一个导出数据的接口,让客户选择数据的导出方式
#include <string>
// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
class IExport {
public:
virtual bool Export(const std::string &data) = 0;
virtual ~IExport(){}
};
class ExportXml : public IExport {
public:
virtual bool Export(const std::string &data) {
//...
//Xml方式输出
return true;
}
};
class ExportJson : public IExport {
public:
virtual bool Export(const std::string &data) {
//...
//Json方式输出
return true;
}
};
class ExportTxt : public IExport {
public:
virtual bool Export(const std::string &data) {
//...
//Txt方式输出
return true;
}
};
//==========================================上面是干活的类,下面是对应的工厂类==================================================
class IExportFactory {
public:
IExportFactory() {
_export = nullptr;
}
virtual ~IExportFactory() {
if (_export) {
delete _export;
_export = nullptr;
}
}
//调用对象自己的的Export函数
bool Export(const std::string &data) {
if (_export == nullptr) {
_export = NewExport();
}
return _export->Export(data);
}
protected:
virtual IExport * NewExport(/* ... */) = 0; //工厂模式的优点是隐藏了创建对象时的复杂过程,而外界直接用创建好的对象就可以了
private:
IExport* _export;
};
class ExportXmlFactory : public IExportFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportXml();
// 可能之后有什么操作
return temp;
}
};
class ExportJsonFactory : public IExportFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportJson;
// 可能之后有什么操作
return temp;
}
};
class ExportTxtFactory : public IExportFactory {
protected:
IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportTxt;
// 可能之后有什么操作
return temp;
}
};
int main () {
IExportFactory * Txt_factory = new ExportTxtFactory();
Txt_factory->Export("hello world");
return 0;
}
代码分析:
- 首先创建一个抽象接口类,规范代码;所有新扩展的接口输出类都继承这个接口,并实现如何输出数据的功能
- 创建一个总的抽象工厂类,再创建接口输出类对应的工厂类,并继承这个抽象工厂类
- 每个接口输出方式对应的工厂类中:实现接口输出类的创建过程,因为创建对象过程比较复杂,就交给工厂创建(工厂就是用来创建对象的)
- 创建出来的对象可以选择返回给用户,也可以选择调用这个对象里面的函数完成特定的功能
总结:工厂就是用来创建对象的,尤其是创建需要很多初始化参数的对象,让外界不用关心创建过程只关心使用
3、要点
-
解决创建过程比较复杂,希望对外隐藏这些细节的场景
- 比如连接池、线程池
-
隐藏对象真实类型(用到了多态)
-
对象创建会有很多参数来决定如何创建,而工厂就干了这个活,外界直接用创建好的对象就可以了
4、本质
- 延迟到子类来选择实现---->子类指的是工厂子类,想得到什么对象,只要创建对应的工厂类对象就能得到想要的对象
5、结构图
抽象工厂设计模式
1、定义
提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。——《设计模式》GoF
2、代码实现
代码背景:实现一个拥有导出导入数据的接口,让客户选择数据的导出导入方式;
#include <string>
// 实现导入、导出数据的接口,导入、导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
class IExport {
public:
virtual bool Export(const std::string &data) = 0;
virtual ~IExport(){}
};
class ExportXml : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportJson : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
class ExportTxt : public IExport {
public:
virtual bool Export(const std::string &data) {
return true;
}
};
//==========================================上面是导出==================================================
class IImport {
public:
virtual bool Import(const std::string &data) = 0;
virtual ~IImport(){}
};
class ImportXml : public IImport {
public:
virtual bool Import(const std::string &data) {
return true;
}
};
class ImportJson : public IImport {
public:
virtual bool Import(const std::string &data) {
return true;
}
};
class ImportTxt : public IImport {
public:
virtual bool Import(const std::string &data) {
return true;
}
};
//==========================================上面是导入==================================================
class IDataApiFactory {
public:
IDataApiFactory() {
_export = nullptr;
_import = nullptr;
}
virtual ~IDataApiFactory() {
if (_export) {
delete _export;
_export = nullptr;
}
if (_import) {
delete _import;
_import = nullptr;
}
}
bool Export(const std::string &data) {
if (_export == nullptr) {
_export = NewExport(); //当子类重写了NewExport,调用的就是子类的了
}
return _export->Export(data);
}
bool Import(const std::string &data) {
if (_import == nullptr) {
_import = NewImport(); //当子类重写了NewExport,调用的就是子类的了
}
return _import->Import(data);
}
protected:
virtual IExport * NewExport(/* ... */) = 0;
virtual IImport * NewImport(/* ... */) = 0;
private:
IExport *_export;
IImport *_import;
};
class XmlApiFactory : public IDataApiFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportXml;
// 可能之后有什么操作
return temp;
}
virtual IImport * NewImport(/* ... */) {
// 可能有其它操作,或者许多参数
IImport * temp = new ImportXml;
// 可能之后有什么操作
return temp;
}
};
class JsonApiFactory : public IDataApiFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportJson;
// 可能之后有什么操作
return temp;
}
virtual IImport * NewImport(/* ... */) {
// 可能有其它操作,或者许多参数
IImport * temp = new ImportJson;
// 可能之后有什么操作
return temp;
}
};
class TxtApiFactory : public IDataApiFactory {
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport * temp = new ExportTxt;
// 可能之后有什么操作
return temp;
}
virtual IImport * NewImport(/* ... */) {
// 可能有其它操作,或者许多参数
IImport * temp = new ImportTxt;
// 可能之后有什么操作
return temp;
}
};
int main () {
IDataApiFactory *factory = new TxtApiFactory();
factory->Import("hello world");
factory->Export("hello world");
return 0;
}
代码分析:
- 和普通的工厂类不同的是一个工厂类既可以创建对应的导出对象,也能创建导入对象
- 抽象工厂设计模式:让有关联的类可以放在一个工厂类中,需要的时候就可以创建对应的对象
- 在本例中,Txt方式的导入、导出是两个功能,但是都是和Txt相关的
- 可以把和Txt功能相关的类都放进Txt工厂中,需要某个Txt功能的时候,就调用相关的函数创建对象就行
- 根据具体业务需求,可以创建完返回该对象,也可以直接调用该对象的成员函数实现某些功能
总结:抽象工厂设计模式的扩展性更强,可用于扩展同一类型下的多种功能(例:Txt方式的导入、导出、转码等)