1. 工厂模式简介

工厂模式顾名思义,工厂就是用来生产产品的。那么在编程的世界里,工厂模式就是用来生产对象的。我们都知道在C++中,可以使用new来创建一个对象,那为何还需要专门设计一个工厂模式来创建对象呢?

其实答案就在刚刚的文字中,当我们使用new来创建对象时,需要知道具体的类名,并且需要给这个类的构造函数传递参数。这个类的使用代码和类的实现代码耦合性太强了,如果将来想给类换个名字(这个很少啦)或者给类增加一个构造参数,那么就需要在每一处使用new创建类对象的地方修改代码,这非常不方便。另外,每次创建类对象都需要事无巨细地传递所有需要的构造参数,这也不方便。

所以工厂模式出现的目的已经呼之欲出了,那就是——封装类对象的创建过程,让类的创建和使用分离开来,彻底解耦合。不论是简单工厂模式、工厂方法模式还是抽象工厂模式,它们的目的都是一样的,都是使创建对象和使用类对象的代码分开,隐藏类对象的创建过程。这样既方便了使用者,也方便类的实现者隐藏类对象的创建过程以及类的具体名字,双赢。

好了,有了以上的工厂模式的前情提要,下面我将依次介绍三种工厂模式:简单工厂模式、工厂方法模式和抽象工厂模式。

工厂模式属于创建型模式(因为它是用来创建对象的嘛)

2. 简单工厂模式

简单工厂模式,顾名思义它真的很简单,很容易懂。我们先来看一段代码。

class Chopsticks {
public:
	virtual string getDesc()const = 0;
	virtual ~Chopsticks() {}
};

class WoodenChopstick : public Chopsticks {
public:
	string getDesc()const override {
		return "一双木头筷子";
	}
};

class StainlessSteelChopstick : public Chopsticks {
public:
	string getDesc()const override {
		return "一双不锈钢筷子";
	}
};

class StonyChopstick : public Chopsticks {
public:
	string getDesc()const override {
		return "一双石头筷子";
	}
};

class ChopsticksFactory {
public:
	static Chopsticks* createChopstick(string type) {
		if (type == "wooden") {
			return new WoodenChopstick();
		}
		else if (type == "stainless") {
			return new StainlessSteelChopstick();
		}
		else if (type == "stony") {
			return new StonyChopstick();
		}
		else {
			return nullptr;
		}
	}
};

int main() {
	Chopsticks* chopstick = ChopsticksFactory::createChopstick("wooden");
	if (chopstick) {
		cout << chopstick->getDesc() << endl;
		delete chopstick;
	}
	return 0;
}

代码很简单,有一个筷子基类,还有三个派生类分别是:木头筷子、不锈钢筷子和石头筷子,还有一个筷子工厂类。通过筷子工厂类的静态方法createChopstick传入对应的名称就可以创建筷子对象了。

这有什么好处呢?虽然现在看起来非常累赘,直接new一个筷子看起来更方便一点,但是如果将来要给筷子增加构造参数时,只需要修改筷子工厂类就好了,不需要修改其他地方,大大滴方便!

以上就是简单工厂的模式的定义和使用了,是不是非常简单?

简单工厂模式人如其名,非常简单。但是它也存在一个问题——如果现在又多了一种塑料筷子,那么这就需要修改筷子工厂类,增加一个else if分支。这违反了开放封闭原则。

开放封闭原则:软件实体(类、模块、函数等)应该能够在不修改现有代码的情况下进行扩展。这意味着当新的需求或变化出现时,我们应该通过添加新的代码来满足这些需求,而不是修改现有的代码。

也就是说,对于简单工厂模式,如果增加一个新类型,必须要修改原来的代码(工厂类的代码) 才可以。

有没有解决这种问题的办法呢?有!那就是工厂方法模式。

3. 工厂方法模式

筷子还是原来那些筷子,但是工厂要大变样了。请看下面的代码:

class FactoryBase {
public:
	virtual Chopsticks* createChopstick() = 0;
	virtual ~FactoryBase() {}
};

class WoodenChopstickFactory : public FactoryBase {
public:
	Chopsticks* createChopstick() override {
		return new WoodenChopstick();
	}
};

class StainlessSteelChopstickFactory : public FactoryBase {
public:
	Chopsticks* createChopstick() override {
		return new StainlessSteelChopstick();
	}
};

class StonyChopstickFactory : public FactoryBase {
public:
	Chopsticks* createChopstick() override {
		return new StonyChopstick();
	}
};

哇哦!现在有四个工厂类了。分别是工厂基类,还有三个派生类:木头筷子工厂、不锈钢筷子工厂、石头筷子工厂。

工厂基类提供了一个创建筷子的接口,三个派生工厂类分别实现了各自的生产筷子的方法,每种筷子都有一个单独的工厂来创建。

那么如何使用呢?

int main() {
	FactoryBase* woodenFactory = new WoodenChopstickFactory();
	FactoryBase* steelFactory = new StainlessSteelChopstickFactory();

	Chopsticks* woodenChopstick = woodenFactory->createChopstick();
	Chopsticks* steelChopstick = steelFactory->createChopstick();

	if(woodenChopstick != nullptr)
		cout << woodenChopstick->getDesc() << endl;
	if(steelChopstick != nullptr)
		cout << steelChopstick->getDesc() << endl;

	delete woodenFactory;
	delete steelFactory;

	delete woodenChopstick;
	delete steelChopstick;

	return 0;
}

这就是工厂方法模式。相比于简单工厂模式,在增加一个新品种的筷子时,仅需创建一个对应的筷子工厂就好了,而无须修改现有代码。

当然它的缺陷也很明显——如果筷子有非常多的种类,那么也需要非常多的工厂类和筷子对应。因为每种筷子工厂只能生产一种筷子。

4. 抽象工厂模式

抽象工厂模式其实和工厂方法模式很像,在抽象方法模式中,每个派生工厂类只生产一个产品,但是在抽象工厂模式中,每个派生工厂类可以生产一个产品族。

一个产品族?这是什么意思?下面给大家举个例子:

上面的代码中,我们一直在创建筷子对象。实际上我们的餐具除了筷子还有勺子、叉子等。如果在工厂基类中增加创建勺子和叉子的接口,那么工厂方法模式就变成了抽象工厂模式。

class AbstractFactory {
public:
	virtual Chopsticks* createChopstick()const = 0; // 创建筷子
	virtual Spoon* createSpoon()const = 0; // 创建勺子
	virtual Fork* createFork()const = 0; // 创建叉子
	virtual ~AbstractFactory() {}
};

那么对于每一个派生工厂类而言,都可以生产各自特色的餐具。比如木头工厂就可以生产木头筷子、木头勺子、木头叉子。那么所谓的产品族在这里指的就是“木头筷子、木头勺子、木头叉子”。

抽象工厂模式的完整测试代码如下:

#include <iostream>
#include <string>

using namespace std;


class Chopsticks {
public:
	virtual string getDesc()const = 0;
	virtual ~Chopsticks() {}
};


class WoodenChopstick : public Chopsticks {
public:
	string getDesc()const override {
		return "一双木头筷子";
	}
};

class StainlessSteelChopstick : public Chopsticks {
public:
	string getDesc()const override {
		return "一双不锈钢筷子";
	}
};

class StonyChopstick : public Chopsticks {
public:
	string getDesc()const override {
		return "一双石头筷子";
	}
};


class Spoon {
public:
	virtual string getDesc()const = 0;
	virtual ~Spoon() {}
};

class WoodenSpoon : public Spoon {
public:
	string getDesc()const override {
		return "一把木头勺子";
	}
};

class StainlessSteelSpoon : public Spoon {
public:
	string getDesc()const override {
		return "一把不锈钢勺子";
	}
};

class StonySpoon : public Spoon {
public:
	string getDesc()const override {
		return "一把石头勺子";
	}
};

class Fork {
public:
	virtual string getDesc()const = 0;
	virtual ~Fork() {}
};

class WoodenFork : public Fork {
public:
	string getDesc()const override {
		return "一把木头叉子";
	}
};

class StainlessSteelFork : public Fork {
public:
	string getDesc()const override {
		return "一把不锈钢叉子";
	}
};

class StonyFork : public Fork {
public:
	string getDesc()const override {
		return "一把石头叉子";
	}
};

class AbstractFactory {
public:
	virtual Chopsticks* createChopstick()const = 0; // 创建筷子
	virtual Spoon* createSpoon()const = 0; // 创建勺子
	virtual Fork* createFork()const = 0; // 创建叉子
	virtual ~AbstractFactory() {}
};

class WoodenFactory : public AbstractFactory {
public:
	Chopsticks* createChopstick()const override {
		return new WoodenChopstick();
	}
	Spoon* createSpoon()const override {
		return new WoodenSpoon();
	}
	Fork* createFork()const override {
		return new WoodenFork();
	}
};

class StainlessSteelFactory : public AbstractFactory {
public:
	Chopsticks* createChopstick()const override {
		return new StainlessSteelChopstick();
	}
	Spoon* createSpoon()const override {
		return new StainlessSteelSpoon();
	}
	Fork* createFork()const override {
		return new StainlessSteelFork();
	}
};

class StonyFactory : public AbstractFactory {
public:
	Chopsticks* createChopstick()const override {
		return new StonyChopstick();
	}
	Spoon* createSpoon()const override {
		return new StonySpoon();
	}
	Fork* createFork()const override {
		return new StonyFork();
	}
};


int main() {
	AbstractFactory* factory = new WoodenFactory();
	Chopsticks* chopstick = factory->createChopstick();
	Spoon* spoon = factory->createSpoon();
	Fork* fork = factory->createFork();
	cout << "我今天用的是:" << chopstick->getDesc() << endl;
	cout << "我的勺子是:" << spoon->getDesc() << endl;
	cout << "我的叉子是:" << fork->getDesc() << endl;
	delete factory;
	delete chopstick;
	delete spoon;
	delete fork;
	return 0;
}

5. 后记

至此,工厂模式就介绍到这里了。做个简单的总结吧。

简单工厂模式通过if else分支来判断该创建哪种类对象。优点是只需要一个工厂类即可,代码量小。缺点是每增加一个新的产品,需要修改工厂的代码,增加新的else if分支。

工厂方法模式通过创建和产品相对应的派生工厂类,实现了每增加一种新的产品只需要增加一个对应的工厂派生类即可,而无须修改原来的代码。缺点是如果产品种类非常多,那么就需要非常多的工厂类。

抽象方法模式和工厂方法模式很类似,区别在于工厂方法模式只能创建一个产品,而抽象工厂模式可以创建一个产品族。


文章基于参考书和个人理解完成,有不正确的地方欢迎大家指正,不吝赐教。

更多推荐