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

目录

1.概述

2.结构图

3.实例

4.优缺点


1.概述

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

2.结构图

        工厂模式的意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个类,工厂模式使一个类的实例化延迟到其子类进行。
        所谓创建对象的接口,就是指的工厂方法。对用户来说,不再由A a = new A(); 这种方式来创建A类对象,而是由工厂方法来创建。至于具体创建哪个,可以由具体的工厂方法来决定。
        其实有两类工厂类:
1)工厂类本身是一个抽象类,由具体的工厂类来创建不同对象,通常是一个具体的工厂只创建一种对象;UML类图如下:

2)参数化的工厂方法,由不同参数决定创建何种对象,通常一个工厂创建多种对象,UML类图如下:

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

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

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

3.实例

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

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

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

//抽象对象"车"
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;
};

上面的类 CCarAdapter 是类适配器,关于适配器的更多介绍,请参考博客设计模式之适配器模式-CSDN博客 ,类 CNullCar 是空对象模式的体现,关于空对象模式的更多介绍,请参考设计模式之空对象模式-CSDN博客

3.1.参数化工厂

CarSimpleFactory.h

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

class CCarSimpleFactory
{
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();
	}

	//[2]
	template<typename Base, typename RCar, typename... Args>
	Base* createEx(Args... args) {
		return new RCar(std::forward<Args>(args)...);
	}

	//[3]
	template <typename Base, typename RCar, typename... Args>
	std::shared_ptr<Base> createEx1(Args... args) {
		std::shared_ptr<Base> p(new RCar(std::forward<Args>(args)...));
		return  p;
	}
};

测试代码:

#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;
}

输出:

上面工厂类 CCarSimpleFactory 中的 create() 函数需要根据传入车类型 type生产出具体的车辆,如果系统扩展业务,需要生产别的车型,那就需要修改create()的代码,那就违反了面向对象的设计原则开闭原则;于是我们陆续改进了create函数,编写了 createEx 和 createEx1 函数,利用模版编程,把需要生产的对象和依赖的参数通过模版传入,解决了工厂对车类型的依赖。

3.2.具体工厂类

CarFactory.h

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

//抽象车辆工厂
class ICarFactory
{
public:
	virtual ~ICarFactory() {}
	virtual ICar* create() = 0;
};

class  CBmwCarFactory : public ICarFactory
{
public:
	ICar* create() override {
		return new CBmwCar();
	}
};

class  CJiliCarFactory : public ICarFactory
{
public:
	ICar* create() override {
		return new CJiliCar();
	}
};

class  CDazhongCarFactory : public ICarFactory
{
public:
	ICar* create() override {
		return new CDazhongCar();
	}
};

class  CPorscheCarFactory : public ICarFactory
{
public:
	ICar* create() override {
		return new CPorscheCar();
	}
};

每个车型都有自己的工厂,扩展起来也比较容易,无需修改之前的代码;例程比较简单,在这里我就不写了。

4.优缺点

优点:

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

缺点:

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

本文的源码下载地址:https://download.csdn.net/download/haokan123456789/88746574?spm=1001.2014.3001.5503

原文地址:https://blog.csdn.net/haokan123456789/article/details/135594759

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_58572.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注