1. 背景介绍
工厂模式使用场景:
- 一种是创建过程涉及复杂的 if-else 分支判断,
- 另一种是对象创建需要组装多个其他类对象或者需要复杂的初始化过程。
2. 不使用工厂
3. 简单工厂实现
#include <bits/stdc++.h>
using namespace std;
enum PRODUCTTYPE {SFJ, XSL, NAS};
/**
* 肥皂基类,定义协议
*/
class soapBase {
public:
virtual void show() = 0; //纯虚函数
virtual ~soapBase() {} //基类析构函数设置为虚函数
};
class SFJSoap : public soapBase {
public:
void show() {
cout << "SFJ Soap!" << endl;
}
};
class XSLSoap : public soapBase {
public:
void show() {
cout << "XSL Soap!" << endl;
}
};
class NASSoap : public soapBase {
public:
void show() {
cout << "NAS Soap!" << endl;
}
};
/**
* 简单工厂实现,肥皂创建工程,负责对象创建工作
*/
class SoapFactory {
public:
soapBase *createSoap(PRODUCTTYPE type) {
switch (type) {
case SFJ:
return new SFJSoap();
break;
case XSL:
return new XSLSoap();
break;
case NAS:
return new NASSoap();
break;
default:
cerr << "Type NOT exist!" << endl;
return nullptr;
break;
}
}
};
int main() {
SoapFactory factory;
soapBase* pSoap1 = factory.createSoap(SFJ);
pSoap1->show();
soapBase* pSoap2 = factory.createSoap(XSL);
pSoap2->show();
soapBase* pSoap3 = factory.createSoap(NAS);
pSoap3->show();
return 0;
}
输出结果
SFJ Soap!
XSL Soap!
NAS Soap!
优点: 对比于直接在主函数中创建对象,通过单独使用工厂类可以使得代码更加清晰,更加符合单一职责原则
缺点:如何要添加新的肥皂品牌就要更改SoapFactory的代码,稍微违反开闭原则(如果少量改动可以接受)
4. 工厂方法实现
#include <bits/stdc++.h>
using namespace std;
enum SOAPTYPE {SFJ, XSL, NAS};
class soapBase {
public:
virtual ~soapBase() {};
virtual void show() = 0;
};
class SFJSoap : public soapBase {
public:
void show() {
cout << "SFJ Soap!" << endl;
}
};
class XSLSoap : public soapBase {
public:
void show() {
cout << "XSL Soap!" << endl;
}
};
class NASSoap : public soapBase {
public:
void show() {
cout << "NAS Soap!" << endl;
}
};
/**
* 工厂基类
*/
class FactoryBase {
public:
virtual soapBase* createSoap() = 0;
};
class SFJFactory : public FactoryBase {
public:
soapBase* createSoap() {
return new SFJSoap();
}
};
class XSLFactory : public FactoryBase {
public:
soapBase* createSoap() {
return new XSLSoap();
}
};
class NASFactory : public FactoryBase {
public:
soapBase* createSoap() {
return new NASSoap();
}
};
int main() {
SFJFactory factory1;
soapBase *pSoap1 = factory1.createSoap();
pSoap1->show();
XSLFactory factory2;
soapBase *pSoap2 = factory2.createSoap();
pSoap2->show();
NASFactory factory3;
soapBase *pSoap3 = factory3.createSoap();
pSoap3->show();
return 0;
}
输出结果
SFJ Soap!
XSL Soap!
NAS Soap!
优点:比简单工厂更加符合开闭原则
缺点:代码更加复杂,每次新增一种肥皂除了写肥皂本身类,还要写对应的工厂类,如果不只按照品牌来分类,而且还需要按产地国家进行划分,那就需要写很多代码,这个时候就可以使用下面的抽象工厂方法
5. 抽象工厂实现
#include <bits/stdc++.h>
using namespace std;
enum SOAPTYPE {SFJ, NAS};
enum COUNTRY {CHINA, JAPAN};
class SoapBase {
public:
virtual ~SoapBase() {};
virtual void show() = 0;
};
class SFJSoap : public SoapBase {
public:
void show() {
cout << "SFJ Soap!" << endl;
}
};
class NASSoap : public SoapBase {
public:
void show() {
cout << "NAS Soap!" << endl;
}
};
class CountryBase {
public:
virtual ~CountryBase() {};
virtual void show() = 0;
};
class China : public CountryBase {
public:
void show() {
cout << "Maked in China!" << endl;
}
};
class Japan : public CountryBase {
public:
void show() {
cout << "Maked in Japan!" << endl;
}
};
class FactoryBase {
public:
virtual SoapBase* createSoap() = 0;
virtual CountryBase* createCountry() = 0;
};
class FactoryA : public FactoryBase {
public:
SoapBase* createSoap() {
return new SFJSoap();
}
CountryBase* createCountry() {
return new China();
};
};
class FactoryB : public FactoryBase {
public:
SoapBase* createSoap() {
return new NASSoap();
}
CountryBase* createCountry() {
return new Japan();
}
};
int main() {
FactoryA factory1;
SoapBase *pSoap1 = nullptr;
CountryBase *pCountry1 = nullptr;
pSoap1 = factory1.createSoap();
pCountry1 = factory1.createCountry();
pSoap1->show();
pCountry1->show();
FactoryB factory2;
SoapBase *pSoap2 = nullptr;
CountryBase *pCountry2 = nullptr;
pSoap2 = factory2.createSoap();
pCountry2 = factory2.createCountry();
pSoap2->show();
pCountry2->show();
return 0;
}
优点:如果分类的情况很多,创建对象比较复杂可以使用这种方法,这种情况比工厂方法容易维护,因为相对来说每个工厂类更加单一
缺点:编码很复杂
5. 工厂模式的作用
- 封装变化:创建逻辑有可能变化,封装成工厂类之后,创建逻辑的变更对调用者透明。
- 代码复用:创建代码抽离到独立的工厂类之后可以复用。
- 隔离复杂性:封装复杂的创建逻辑,调用者无需了解如何创建对象。
- 控制复杂度:将创建代码抽离出来,让原本的函数或类职责更单一,代码更简洁。
6. 工厂方法模式新示例(更推荐)
6.1 概述
- 用工厂方法代替用于对象构造函数的直接调用(new)
- 工厂方法返回的对象通常称为产品
6.2 编码
使用智能指针改造源代码
#include <bits/stdc++.h>
using namespace std;
/**
* 产品抽象类
*/
class Product {
public:
virtual ~Product() {}
virtual string Operation() const = 0;
};
/**
* 具体产品类1
*/
class ConcreteProduct1 : public Product {
public:
string Operation() const override {
return "{Result of the ConcreteProduct1}";
}
};
/**
* 具体产品类2
*/
class ConcreteProduct2 : public Product {
public:
string Operation() const override {
return "{Result of the ConcreteProduct2}";
}
};
/**
* 工厂类,抽象类
*/
class Creator {
public:
virtual ~Creator(){};
virtual shared_ptr<Product> FactoryMethod() const = 0;
string SomeOperation() const {
shared_ptr<Product> product = FactoryMethod();
string result = "Creator: The same creator's code has just worked with " + product->Operation();
return result;
}
};
/**
* 工厂子类1
*/
class ConcreteCreator1 : public Creator {
public:
shared_ptr<Product> FactoryMethod() const override {
return make_shared<ConcreteProduct1> ();
}
};
/**
* 工厂子类2
*/
class ConcreteCreator2 : public Creator {
public:
shared_ptr<Product> FactoryMethod() const override {
return make_shared<ConcreteProduct2>();
}
};
/**
* @brief 客户端代码
* @param creator 工厂对象引用
*/
void ClientCode(const Creator& creator) {
cout << "Client: I'm not aware of the creator's class, but it still works.\n"
<< creator.SomeOperation() << endl;
}
int main() {
cout << "App: Launched with the ConcreteCreator1.\n";
shared_ptr<Creator> creator = make_shared<ConcreteCreator1>();
ClientCode(*creator);
cout << endl;
cout << "App: Launched with the ConcreteCreator2.\n";
shared_ptr<Creator> creator2 = make_shared<ConcreteCreator2>();
ClientCode(*creator2);
return 0;
}
输出:
App: Launched with the ConcreteCreator1.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with {Result of the ConcreteProduct1}
App: Launched with the ConcreteCreator2.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with {Result of the ConcreteProduct2}
6.3 总结
工厂有基类,产品有基类,这里的基类是抽象类,尽量依赖抽象而不依赖实现;
但是这里也注意到其实不可能完全不知道工厂子类,在使用工厂创建对象的时候需要指定具体的工厂子类类型,但是后续的客户端可以只依赖于工厂抽象类
7. 抽象工厂模式新示例
7.1 概述
多维度的分类,工厂的工厂
7.2 编码
#include <bits/stdc++.h>
using namespace std;
/**
* 抽象产品A,对应一个产品系列
*/
class AbstractProductA {
public:
virtual ~AbstractProductA() {};
virtual string UsefulFunctionA() const = 0;
};
/**
* A系列的具体产品A1
*/
class ConcreteProductA1 : public AbstractProductA {
public:
string UsefulFunctionA() const override {
return "The result of the product A1.";
}
};
/**
* A系列的具体产品A2
*/
class ConcreteProductA2 : public AbstractProductA {
string UsefulFunctionA() const override {
return "The result of the product A2.";
}
};
/**
* 产品产品B,对应另外一个产品系列
*/
class AbstractProductB {
public:
virtual ~AbstractProductB(){};
virtual string UsefulFunctionB() const = 0;
// 与A系列产品的协作
virtual string AnotherUsefulFunctionB(const AbstractProductA& collaborator) const = 0;
};
/**
* B系列具体产品B1
*/
class ConcreteProductB1 : public AbstractProductB {
public:
string UsefulFunctionB() const override {
return "The result of the product B1.";
}
string AnotherUsefulFunctionB(const AbstractProductA& collaborator) const override {
const string result = collaborator.UsefulFunctionA();
return "The result of the B1 collaborating with ( " + result + " )";
}
};
/**
* B系列具体产品B2
*/
class ConcreteProductB2 : public AbstractProductB {
public:
string UsefulFunctionB() const override {
return "The result of the product B2.";
}
string AnotherUsefulFunctionB(const AbstractProductA& collaborator) const override {
const string result = collaborator.UsefulFunctionA();
return "The result of the B2 collaborating with ( " + result + " )";
}
};
/**
* 抽象工厂类
*/
class AbstractFactory {
public:
virtual shared_ptr<AbstractProductA> CreateProductA() const = 0;
virtual shared_ptr<AbstractProductB> CreateProductB() const = 0;
};
/**
* 具体工厂类1
*/
class ConcreteFactory1 : public AbstractFactory {
public:
shared_ptr<AbstractProductA> CreateProductA() const override {
return make_shared<ConcreteProductA1>();
}
shared_ptr<AbstractProductB> CreateProductB() const override {
return make_shared<ConcreteProductB1>();
}
};
/**
* 具体工厂类2
*/
class ConcreteFactory2 : public AbstractFactory {
public:
shared_ptr<AbstractProductA> CreateProductA() const override {
return make_shared<ConcreteProductA2>();
}
shared_ptr<AbstractProductB> CreateProductB() const override {
return make_shared<ConcreteProductB2>();
}
};
void ClientCode(const AbstractFactory &factory) {
shared_ptr<const AbstractProductA> product_a = factory.CreateProductA();
shared_ptr<const AbstractProductB> product_b = factory.CreateProductB();
cout << product_a->UsefulFunctionA() << endl;
cout << product_b->UsefulFunctionB() << endl;
}
int main() {
cout << "Client: Testing client code with the first factory type" << endl;
shared_ptr<ConcreteFactory1> f1 = make_shared<ConcreteFactory1>();
ClientCode(*f1);
cout << endl;
cout << "Client: Testing the same client code with the second factory type" << endl;
shared_ptr<ConcreteFactory2> f2 = make_shared<ConcreteFactory2>();
ClientCode(*f2);
return 0;
}
输出:
Client: Testing client code with the first factory type
The result of the product A1.
The result of the product B1.
Client: Testing the same client code with the second factory type
The result of the product A2.
The result of the product B2.
客户端代码可以重复利用
7.3 总结
优点:
- 更加符合单一职责原则
- 更加符合开闭原则
- 减少客户端和具体产品代码耦合
缺点:
- 编码复杂
对比简单工厂、工厂方法、抽象工厂总结
- 简单工厂:大多数情况下,简单工厂是工厂方法或抽象工厂的中间步骤,简单工厂类通常没有子类,当从简单工厂中提取出子类后,它更像工厂方法模式了
- 工厂方法:创建型设计模式,存在工厂基类和子类
- 抽象工厂:创建型设计模式,工厂方法解决的是根据一种分类方法(一种角度的扩展),设计一种模式解决它们的对象创建问题,而抽象工厂模式适用于不只一种分类方法(多种角度的扩展)。比如说现在要创建交通运输工具对象,按照形态分为汽车;按照发动类型分为内燃机和喷气式发动机;按照控制方式分为方向盘和操纵杆,那么就可以使用抽象工厂,抽象工厂又被称为工厂的工厂