工厂模式(Factory)
本文是 Gerald 对于设计模式的一些思考,下面的速记表会随着博客的不断演进而增加,喜欢的话可以 follow 一下哦
名称 | 类别 | 速记 | 解决了什么问题 | 如何解决 |
---|---|---|---|---|
工厂模式 | 对象创建 | 多态new,与子类的初始化解耦 | 虽然【子类的使用】已经使用了【父类指针】实现【多态】,但是 new 并没有多态,这就导致对子类的使用并没有完全解耦 | 将【子类的 new 方法】变为调用【子类工厂的Create 方法】,从而将【子类的创建】也进行解耦 |
参考:C++ 设计模式 www.bilibili.com/video/BV1Yr…。本文是对于该视频的读书笔记和个人思考
需求:设计一个【分割器】及其【展示前台】,该前台可以进行各种文件的分割,比如视频分割、文件分割等
需求扩展:以后可能会添加其他分割器,比如视频分割器。
不是这个需求哦!需求应该是,可能会使用该前台作为不同的文件分割器,比如专用于【视频分割】的展示前台,专用于【文件分割】的展示前台 。
下面的代码是自己手搓的,可以直接运行,用于对比两种不同方法的效果
// 原始代码
#include <iostream>
using namespace std;
// 父类
class ISplitter {
public:
virtual ~ISplitter(){};
virtual void split()=0;
};
// 子类1
class BinarySplitter : public ISplitter {
public:
void split() {
cout << "Split binary done." << endl;
return;
}
};
// 子类2
class FileSplitter : public ISplitter {
public:
virtual void split() {
cout << "Split file done." << endl;
return;
}
};
// 界面使用
class MainForm {
public:
virtual void clickButton() {
// 在这里与具体的类耦合了
ISplitter* splitter = new BinarySplitter();
// 虽然这里使用到了多态
splitter->split();
}
};
int main() {
MainForm form;
form.clickButton();
return 0;
}
// 工厂方法
#include <iostream>
using namespace std;
// 父类
class ISplitter {
public:
virtual ~ISplitter(){};
virtual void split()=0;
};
// 子类1
class BinarySplitter : public ISplitter {
public:
void split() {
cout << "Split binary done." << endl;
return;
}
};
// 子类2
class FileSplitter : public ISplitter {
public:
virtual void split() {
cout << "Split file done." << endl;
return;
}
};
// 工厂基类
class SplitterFactory {
public:
virtual ISplitter* Create()=0;
virtual ~SplitterFactory(){};
};
// 工厂子类1
class BinarySplitterFactory : public SplitterFactory {
virtual ISplitter* Create() {
return new BinarySplitter();
}
};
// 工厂子类2
class FileSplitterFactory : public SplitterFactory {
virtual ISplitter* Create() {
return new FileSplitter();
}
};
// 界面使用
class MainForm {
SplitterFactory* factory;
public:
//要求 MianForm 接受一个 factory 的初始化参数
MainForm(SplitterFactory* f) { factory = f; }
virtual void clickButton() {
// 通过将依赖转移到工厂类从而与子类解耦
ISplitter* splitter = factory->Create();
splitter->split();
}
};
int main() {
MainForm form(new BinarySplitterFactory());
form.clickButton();
return 0;
}
总结:工厂模式只是将对于子类创建的依赖从 MainForm 类中移动到外部,这样子当我们想创建多个不同功能的 MainForm 类的时候,就可以直接传入 Factory 的方式来进行调用。这样子MainForm 类似乎变成了一个 dumb Component(React 中的一个概念),没有任何外部依赖,只依赖于传入的参数决定其行为,可复用性极高。
比如,如果我们想创建一个 文件分割器的展示前台的话,那么我们就可以直接这么写,不需要改动 MainForm 的代码:
int main() {
MainForm form(new BinarySplitterFactory());
form.clickButton();
// 一个新的界面
MainForm form2(new FileSplitterFactory());
form.clickButton();
return 0;
}
但如果对于原本的这个写法,那么就需要更改 MainForm 的代码,创建一个新的类。导致 MainForm 的大部分代码是冗余的,这是因为 MainForm 依然有着子类的依赖。
但是,如果需求变化,没有 MainForm 这个【展示前台】的话,其实并没有必要使用工厂方法。因为这种情况下没有必要将初始化过程进行解耦,使用工厂模式反而会更麻烦。因此,设计模式不能胡乱使用,而是需要根据具体场景的可变部分的需求。
int main() {
ISplitter* splitter = new BinarySplitter();
splitter->split();
ISplitter* splitter = new FileSplitter();
splitter->split();
}
int main() {
// 多一步反而现得更加臃肿了
SplitterFactory* bsf = new BinarySplitterFactory();
ISplitter* splitter = bsf->Create();
splitter->split();
SplitterFactory* fsf = new FileSplitterFactory();
ISplitter* splitter = fsf->Create();
splitter->split();
}
如果想要使用工厂模式,需要的情况就是希望当前组件(MainForm)对于子类(XXXSplit)完全解耦,包括使用(Split)和初始化(new),以此达到当前组件变成一个 dumb component 的目的。
文章中很好玩的话,记录一下
实际上并不是把依赖给消灭掉了,而是把依赖给赶到某个具体的地方了。一个例子是,就好像你把一只猫关到笼子里,而不是在你的代码里跳来跳去。