Gerald 的设计模式读书笔记 —— (一)工厂模式

46 阅读3分钟

工厂模式(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 的目的。

文章中很好玩的话,记录一下

实际上并不是把依赖给消灭掉了,而是把依赖给赶到某个具体的地方了。一个例子是,就好像你把一只猫关到笼子里,而不是在你的代码里跳来跳去。