工厂模式的核心目的,是为对象的创建提供一个统一的接口,并把具体类的实例化工作延迟到子类中完成。

当系统中涉及的对象种类繁多、创建过程复杂多样时,直接在调用端 new 对象会让代码变得混乱。工厂模式通过约定统一的创建入口,把创建逻辑收敛到专门的角色里,从而提高内聚、降低耦合。

它定义了创建对象的接口,封装了对象的创建过程,使得具体类的实例化工作可以延迟到子类中去实现。

工厂模式的几种常见写法

工厂模式在实现上有好几种形式,下面分别给出示例。

1. 简单的静态接口函数

最基础的形式是在产品类内部提供一个静态创建函数,把构造函数私有化,调用端只能通过静态接口得到对象。

class Product
{
public:
	/**
	 * @brief  create a Product
	 */
	static Product *create()
	{
		return new Product;
	}
private:
	Product(){}
};

2. 抽象工厂类创建(一)

把创建接口抽象到独立的工厂类中,由具体工厂子类实现实际的 new 操作,调用端面向抽象工厂编程。

class Product
{

public:
	Product(){}
};

class  Factory
{
public:
	virtual	Product * create() = 0;


};

class ProductFactory : public Factory
{
public:
	virtual Product *create()override
	{

		return new Product;
	}


};




int main(int argc, char *argv[])
{
	Factory * factory = new ProductFactory;
	Product* product = factory->create();
	system("pause");
	return 0;
}
//还可以进一步 对访问权限封装

3. 模板工厂类创建

借助 C++ 模板和模板特化,可以让工厂按照产品类型自动展开对应的创建逻辑,也可以改写成模板函数的特化版本。

class Product
{

public:
	void init(){ cout << __FUNCTION__ << endl; };
	Product(){}
};


template< class T>
class Factory
{
public:
	Factory(){};
	virtual T *create();
};


template<>
class Factory<Product>
{
public:
	Factory(){};

	virtual Product *create()
	{
		auto ins = new Product;
		ins->init();
		return ins;
	}
};


int main(int argc, char *argv[])
{
	auto *factory = new  Factory<Product>();
	factory->create();

	return 0;
}
//也可以用模板函数创建,各自的特化版本

4. 抽象工厂创建(二)

当一个工厂需要生产一整族相关产品时,可以在抽象工厂里定义多个创建接口,由具体工厂一次性给出整族对象的实现。

class Fruit
{
public:
	Fruit(){}
};

class Apple :public Fruit
{
public: Apple(){};
};

class Peach :public Fruit
{
public: Peach(){};
};




class  Factory
{
public:
	virtual	Fruit *createApple() = 0;
	virtual	Fruit *createPeach() = 0;

};

class FruitFactory : public Factory
{
public:
	Fruit *createApple()override
	{
		return new Apple;
	}
	Fruit *createPeach()override
	{
		return new Peach;
	}

};




int main(int argc, char *argv[])
{

	Factory * factory = new FruitFactory;

	Fruit* apple = factory->createApple();
	Fruit *peach = factory->createPeach();


	system("pause");
	return 0;
}