设计模式之工厂模式

发布时间:2024年01月15日

目录

1.概述

2.结构图

3.实例

4.优缺点


1.概述

工厂模式也是平时我们编程用的比较多的一种行为设计模式,它提供了一种创建对象的最佳方式。工厂模式提供了一种创建对象的方式,而无需指定要创建的具体类。工厂模式属于创建型模式,它在创建对象时提供了一种封装机制,将实际创建对象的代码与使用代码分离。

2.结构图

工厂模式创建对象(参数化的工厂),UML类图如下:

工厂模式包含以下几个核心角色:

  • 抽象产品(Abstract Product):定义了产品的共同接口或抽象类。它可以是具体产品类的父类或接口,规定了产品对象的共同方法。上图中ICar就是具体车的一个抽象,规定它们的共同的一个接口run()。
  • 具体产品(Concrete Product):实现了抽象产品接口,定义了具体产品的特定行为和属性。上图中的CBmwCar、CDazhongCar和CPorscheCar都是具体的车型。
  • 抽象工厂(Abstract Factory):声明了创建产品的抽象方法,可以是接口或抽象类。它可以有多个方法用于创建不同类型的产品。
  • 具体工厂(Concrete Factory):实现了抽象工厂接口,负责实际创建具体产品的对象。

备注:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

3.实例

抽象车类和具体车类如下:Car.h

#include <iostream>
#include <assert.h>

//抽象对象"车"
class ICar
{
public:
	virtual ~ICar() {}
	virtual void run() = 0;
	virtual bool isNull() = 0;
};

//对象适配器
class CCarAdapter : public ICar
{
public:
	void run() override {
		assert(0);
	}
	bool isNull() override {
		return false;
	}
};

//空对象模式实现
class CNullCar : public ICar
{
public:
	void run() override {
		assert(0);
	}
	bool isNull() override {
		return true;
	}
};

//宝马车
class CBmwCar : public CCarAdapter
{
public:
	void run() override {
		std::cout << "Bmw car is running...\n";
	}
};

//吉利车
class CJiliCar : public CCarAdapter
{
public:
	void run() override {
		std::cout << "Jili car is running...\n";
	}
};

//大众车
class CDazhongCar : public CCarAdapter
{
public:
	void run() override {
		std::cout << "Dazhong car is running...\n";
	}
};

//保时捷豪车
class CPorscheCar : public CCarAdapter
{
public:
	void run() override {
		std::cout << "Porsche car is running...\n";
	}
};

//长安车
class CChangAnCar : public CCarAdapter
{
public:
	explicit CChangAnCar(int n) :m_n(n) {

	}
	void run() override {
		std::cout << "ChangAn " << m_n << " cars is running...\n";
	}

private:
	int m_n;
};

参数化工厂:CarFactory.h

#include "Car.h"
#include <memory>

enum CarType
{
	eBMWCar = 0, //宝马车 
	eJILICar, // 吉利车
	eDAZHONGCar, // 大众车
	eCHANGANCar, //长安车
	ePORSCHECar, //保时捷
};

class CCarFactory
{
public:
	//[1]
	ICar* create(int type) {
		std::unique_ptr<ICar> temp;
		switch (type) {
		case eBMWCar:
			temp.reset(new CBmwCar());
			break;
		case eJILICar:
			temp.reset(new CJiliCar());
			break;
		case eDAZHONGCar:
			temp.reset(new CDazhongCar());
			break;
		case ePORSCHECar:
			temp.reset(new CPorscheCar());
			break;
		default:
			//assert(0);
			temp.reset(new CNullCar());
			break;
		}
		return temp.release();
	}
};

测试代码:

#include <iostream>
#include "Car.h"
#include "CarFactory.h"

int main()
{
	std::unique_ptr<ICar> pCar;
	std::unique_ptr<CCarFactory> factory(new CCarFactory());

	//[1]
	std::cout << "Car Factory mode1:\n";
	pCar.reset(factory->create(eBMWCar)); //宝马
	pCar->run();

	pCar.reset(factory->create(eDAZHONGCar)); //大众
	pCar->run();

	pCar.reset(factory->create(eJILICar)); //吉利
	pCar->run();

	pCar.reset(factory->create(11)); //不生产这种车
	if (pCar->isNull()) {
		std::cout << "Carfactory not product the 11 type car!!!\n";
	}

	pCar.reset(factory->create(ePORSCHECar)); //保时捷
	pCar->run();
    return 0;
}

输出:

4.优缺点

优点:

1) 良好的时装性,代码结构清晰。一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,只要知道这个产品的类名(或约束字符串)就可以了,不用知道包建对象的艰辛过程,降低模块间的耦合。
2) 工厂方法模式的扩展性非常优秀。在增加产品类的情况下,只要适当地修改具体的工厂类或扩展一个工厂类,就可以完成拥抱变化。
3) 屏蔽产品类。这一特点非常重要,产品类的实现如何变化,调用者都不需要关心,它只需要关心产品的接口,只要接口保持不变,系统中的上层模块就不要发生变化。因为产品类的实例化工作是由工厂类负责的,一个产品对象具体由哪一个产品生成是由工厂类决定的。在数据库开发中,大家应该能够深刻体会到工厂方法模式的好处:如果使用DBC连接数据库,数据库从MysQL切换到Oracle,需要改动的地方就是切换一下驱动名称(前提条件是SOL语包是标准语句),其他的都不需要修改,这是工厂方法模式灵活性的一个直接案例。
4) 工厂方法模式是典型的解耦框架。高层模块值需要知道产品的抽象类,其他的实现类都不用关心,符合迪采特法则,我不需要的就不要去交流:也符合依赖倒置原则,只依赖产品类的抽象;当然也符合单氏替换原则,使用产品子类替换产品父类,没问题。

缺点:

1) 增加代码复杂度:引入工厂模式会增加代码的复杂度,因为需要定义工厂类来管理对象的创建,同时还需要考虑如何处理异常和错误情况。
2) 违反开闭原则:开闭原则是指软件实体应该对扩展开放,对修改封闭。然而,工厂模式在一定程度上违反了这一原则,因为它在编译时确定了类的结构和关系,导致对新的类结构不适应,难以扩展和维护。
3) 不易调试:由于工厂模式将对象创建的逻辑封装在工厂类中,当出现错误或异常时,调试可能会变得更加困难,因为问题可能出现在隐藏的工厂类中。

文章来源:https://blog.csdn.net/haokan123456789/article/details/135594759
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。