C++工厂模式(简单工厂、工厂方法、抽象工厂)

本文深入探讨了工厂模式在软件设计中的应用,从简单工厂模式开始,逐步过渡到工厂方法和抽象工厂模式。通过代码示例展示了如何创建和扩展产品对象,同时阐述了各种模式的优点和不足。简单工厂模式虽然易于理解,但不满足开闭原则;工厂方法通过基类指针实现多态,增强了扩展性;抽象工厂则能创建一组相关产品,更好地模拟现实世界中的产品簇。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

为什么要使用工厂模式

主要是对对象的创建进行了一个封装;
因此也属于创建型模式

意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

主要解决:主要解决接口选择的问题。

优点

  1. 一个调用者想创建一个对象,只要知道其名称就可以了;
  2. 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以;
  3. 屏蔽产品的具体实现,调用者只关心产品的接口。

缺点

每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖

简单工厂(Simple Factory)

代码

首先是具体产品的实现继承关系

// 系列产品
class Car
{
public:
	Car(string name) :_name(name) {}
	virtual void show() = 0;
protected:
	string _name;
};
class Bmw:public Car
{
public:
	Bmw(string name) :Car(name) {}
	void show()
	{
		cout << "获取了一辆宝马汽车:" << _name << endl;
	}
};
class Audi :public Car
{
public:
	Audi(string name) :Car(name) {}
	void show()
	{
		cout << "获取了一辆奥迪汽车:" << _name << endl;
	}
};

接下来是简单工厂的实现:

// 产品枚举
enum Cartype
{
	BMW, AUDI
};
// 简单工厂类
class SimpleFactory
{
public:
	// 用户想要创建一个对象,只需要知道名称就可以了
	Car* createCar(Cartype ct)
	{
		switch (ct)
		{
		case BMW:
			return new Bmw("x6");
		case AUDI:
			return new Audi("a8");
		default:
			cerr << "传入参数错误:" << ct << endl;
		}
		return nullptr;
	}
};

应用

具体的使用规则如下:

int main()
{
	unique_ptr<SimpleFactory> fac(new SimpleFactory());
	unique_ptr<Car> p1(fac->createCar(BMW));
	unique_ptr<Car> p2(fac->createCar(AUDI));

	p1->show();
	p2->show();

	return 0;
}

需要注意的是:
为了更好地释放资源,这里使用了智能指针(需要加入头文件#include <memory>);
也可以直接使用new的方法,代码如下:

	SimpleFactory* fac = new SimpleFactory();
	Car* p1 = fac->createCar(BMW);
	Car* p2 = fac->createCar(AUDI);

	p1->show();
	p2->show();

	delete fac;
	delete p1;
	delete p2;

使用普通指针(new)的时候就需要注意一定记得delete

我们来看运行的结果:
在这里插入图片描述

不足

可以看到,简单工厂可以做到,让用户创建对象的时候只需要知道对象的名称BMWAUDI)就好,而不需要关心创建对象的细节(BMW是如何建造的、型号是什么等等细节)。

当然缺点也很明显:
每当我们想要扩展对象的时候(增加BENZ的对象)就需要在SimpleFactory类中添加代码,增加switch后面的case选项。这样一来,就需要修改源代码。灵活性非常的差!!!

那么,能不能做到添加对象的时候,不对现有代码进行修改呢?(也就是我们开发软件时候需要遵守的开-闭原则

tips:
什么是开-闭原则呢?
扩展开放、对修改关闭;
也就是说,我们可以添加代码,但是添加代码的时候不能够对现有的代码进行修改。
这样的代码才能算是好代码!!!

于是乎,便有了 工厂方法

工厂方法(Factory Method)

工厂方法的思想就是定义一个Factory基类,基类中定义了一个纯虚函数(创建产品);
之后定义派生类(具体产品的工厂)负责创建对应的产品。
可以做到不同的产品在不同的工厂里面创建,能够对现有工厂以及产品的修改关闭

代码

同样的,具体产品的实现和继承同上:

// 系列产品
class Car
{
public:
	Car(string name) :_name(name) {}
	virtual void show() = 0;
protected:
	string _name;
};
class Bmw:public Car
{
public:
	Bmw(string name) :Car(name) {}
	void show()
	{
		cout << "获取了一辆宝马汽车:" << _name << endl;
	}
};
class Audi :public Car
{
public:
	Audi(string name) :Car(name) {}
	void show()
	{
		cout << "获取了一辆奥迪汽车:" << _name << endl;
	}
};

接下来是工厂方法的实现:

// 基类(包含纯虚函数,不能实例化对象)
class Factory
{
public:
	virtual Car* createCar(string name) = 0;
};
// 宝马汽车工厂,负责生产宝马汽车
class BmwFac: public Factory
{
public:
	Car* createCar(string name)
	{
		return new Bmw(name);
	}
};
// 奥迪汽车工厂,负责生产奥迪汽车
class AudiFac :public Factory
{
public:
	Car* createCar(string name)
	{
		return new Audi(name);
	}
};

应用

同样的,使用规则如下:

int main()
{
	unique_ptr<Factory> bmwfty(new BmwFac());
	unique_ptr<Factory> audifty(new AudiFac());
	unique_ptr<Car> p1 (bmwfty->createCar("X6"));
	unique_ptr<Car> p2 (audifty->createCar("A8"));
	
	p1->show();
	p2->show();

	return 0;
}

注意
可以看到这一次的代码和之前简单工厂的不同:
简单工厂unique_ptr<SimpleFactory> fac(new SimpleFactory())
工厂方法unique_ptr<Factory> bmwfty(new BmwFac())
也就是说,工厂方法是用基类指针实例化派生类对象,这也是动态多态发生的条件。这样的话,就能够实现多态了!

之后的unique_ptr<Car> p1 (bmwfty->createCar("X6"))有没有更贴近生活呢?
我去买车,进到一家宝马4S店(对应具体的bmwfty对象),然后看上了心仪的车型bmw X6,然后告诉店员:“我想要一辆宝马X6”。之后办理完手续,就可以开心地提车了!

运行结果如下:
在这里插入图片描述

不足

工厂方法解决了简单工厂的问题(无法对修改关闭),但是它也有自己的局限:
试想一下,宝马工厂里面只是售卖成品汽车吗?
应该不是吧,作为一家成熟的工厂,除了汽车之外,还有一系列配套的零件产品:比如说:轮胎车灯真皮豪华座椅等等。也就是说,跟汽车相关联的有一整个产品簇

但是我们的宝马工厂BmwFac里面只有一个createCar方法,如果想要添加产品的话,就需要增加新的类。但是这些产品其实都应该在一个BmwFac工厂里面。这才是现实的逻辑,另外,工厂类太多,会不好维护。

于是乎,抽象工厂 应运而生。

抽象工厂(Abstract Factory)

抽象工厂的思想是:
把有关联关系的,属于一个产品簇的所有产品创建的接口函数,放在一个抽象工厂里面AbstractFactory,派生类(具体产品的工厂)应该负责创建该产品簇里面所有的产品。

代码

这一次,除了汽车产品外,我们再添加一个车灯产品,系列产品的实现和继承关系代码如下:

// 系列产品1:汽车
class Car
{
public:
	Car(string name) :_name(name) {}
	virtual void show() = 0;
protected:
	string _name;
};
class Bmw:public Car
{
public:
	Bmw(string name) :Car(name) {}
	void show()
	{
		cout << "获取了一辆宝马汽车:" << _name << endl;
	}
};
class Audi :public Car
{
public:
	Audi(string name) :Car(name) {}
	void show()
	{
		cout << "获取了一辆奥迪汽车:" << _name << endl;
	}
};
// 系列产品2:车灯
class Light
{
public:
	virtual void show() = 0;
};
class BmwLight : public Light
{
public:
	void show() { cout << "BMW light!" << endl; }
};
class AudiLight : public Light
{
public:
	void show() { cout << "Audi light!" << endl; }
};

接下来是抽象工厂的实现:

// 工厂方法 => 抽象工厂(对有一组关联关系的产品簇提供产品对象的统一创建)
class AbstractFactory
{
public:
	virtual Car* createCar(string name) = 0; // 工厂方法 创建汽车
	virtual Light* createCarLight() = 0; // 工厂方法 创建汽车关联的产品,车灯
};
// 宝马工厂
class BMWFactory : public AbstractFactory
{
public:
	Car* createCar(string name)
	{
		return new Bmw(name);
	}
	Light* createCarLight()
	{
		return new BmwLight();
	}
};
// 奥迪工厂
class AudiFactory : public AbstractFactory
{
public:
	Car* createCar(string name)
	{
		return new Audi(name);
	}
	Light* createCarLight()
	{
		return new AudiLight();
	}
};

应用

对于抽象工厂的使用如下:

int main()
{
	unique_ptr<AbstractFactory> bmwfty(new BMWFactory());
	unique_ptr<AbstractFactory> audifty(new AudiFactory());
	unique_ptr<Car> p1(bmwfty->createCar("X6"));
	unique_ptr<Car> p2(audifty->createCar("A8"));
	unique_ptr<Light> l1(bmwfty->createCarLight());
	unique_ptr<Light> l2(audifty->createCarLight());

	p1->show();
	l1->show();

	p2->show();
	l2->show();

	return 0;
}

运行结果如下:
在这里插入图片描述

参考资料

【1】工厂模式|菜鸟教程

抽象工厂方法模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一个接口,用于创建一系列相关或依赖对象的家族,而无需指定它们具体的类。 在 C++ 中,抽象工厂方法模式通常通过定义一个抽象基类来实现。这个抽象基类定义了一系列纯虚函数,用于创建不同类型的产品对象。然后,针对不同的产品族,创建具体的工厂类,这些工厂类实现了抽象基类中定义的纯虚函数,用于创建具体的产品对象。 以下是一个简单抽象工厂方法模式的示例代码: ```c++ // 抽象产品类 A class AbstractProductA { public: virtual void operationA() = 0; }; // 抽象产品类 B class AbstractProductB { public: virtual void operationB() = 0; }; // 具体产品类 A1 class ConcreteProductA1 : public AbstractProductA { public: void operationA() { std::cout << "ConcreteProductA1::operationA()" << std::endl; } }; // 具体产品类 A2 class ConcreteProductA2 : public AbstractProductA { public: void operationA() { std::cout << "ConcreteProductA2::operationA()" << std::endl; } }; // 具体产品类 B1 class ConcreteProductB1 : public AbstractProductB { public: void operationB() { std::cout << "ConcreteProductB1::operationB()" << std::endl; } }; // 具体产品类 B2 class ConcreteProductB2 : public AbstractProductB { public: void operationB() { std::cout << "ConcreteProductB2::operationB()" << std::endl; } }; // 抽象工厂类 class AbstractFactory { public: virtual AbstractProductA* createProductA() = 0; virtual AbstractProductB* createProductB() = 0; }; // 具体工厂类 1 class ConcreteFactory1 : public AbstractFactory { public: AbstractProductA* createProductA() { return new ConcreteProductA1(); } AbstractProductB* createProductB() { return new ConcreteProductB1(); } }; // 具体工厂类 2 class ConcreteFactory2 : public AbstractFactory { public: AbstractProductA* createProductA() { return new ConcreteProductA2(); } AbstractProductB* createProductB() { return new ConcreteProductB2(); } }; int main() { AbstractFactory* factory1 = new ConcreteFactory1(); AbstractProductA* productA1 = factory1->createProductA(); AbstractProductB* productB1 = factory1->createProductB(); productA1->operationA(); // 输出:ConcreteProductA1::operationA() productB1->operationB(); // 输出:ConcreteProductB1::operationB() AbstractFactory* factory2 = new ConcreteFactory2(); AbstractProductA* productA2 = factory2->createProductA(); AbstractProductB* productB2 = factory2->createProductB(); productA2->operationA(); // 输出:ConcreteProductA2::operationA() productB2->operationB(); // 输出:ConcreteProductB2::operationB() return 0; } ``` 在上面的示例代码中,我们定义了两个抽象产品类 `AbstractProductA` 和 `AbstractProductB`,以及四个具体产品类 `ConcreteProductA1`、`ConcreteProductA2`、`ConcreteProductB1` 和 `ConcreteProductB2`。然后,我们定义了一个抽象工厂类 `AbstractFactory`,它包含两个纯虚函数,用于创建不同类型的产品对象。最后,我们定义了两个具体工厂类 `ConcreteFactory1` 和 `ConcreteFactory2`,它们分别实现了 `AbstractFactory` 中定义的纯虚函数,用于创建具体的产品对象。 在 `main` 函数中,我们首先创建了一个 `ConcreteFactory1` 对象,然后使用它创建了一个 `ConcreteProductA1` 和一个 `ConcreteProductB1` 对象,并调用了它们的成员函数。然后,我们创建了一个 `ConcreteFactory2` 对象,使用它创建了一个 `ConcreteProductA2` 和一个 `ConcreteProductB2` 对象,并调用了它们的成员函数。 通过这种方式,我们可以轻松地创建一系列相关或依赖对象的家族,并且无需指定它们具体的类。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值