创建型模式2——工厂模式(简单工厂、工厂方法、抽象工厂)

2023-11-11

简单工厂

模式动机

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

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

简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。简单工厂模式结构比较简单,其核心是工厂类的设计:
在这里插入图片描述

简单工厂模式中包含以下的几个角色:

  1. Factory(工厂角色):工厂类,它是简单工厂的核心,工厂类可以被外部直接调用,创建所需的产品对象,在工厂类中提供了静态的工厂方法factoryMethod();它的返回类型为抽象产品类型Product。
  2. Product(抽象产品角色):是工厂类所创建所有对象的父类封装了各种产品对象的公有方法,它的引入提高了灵活性,使得在工厂类中只需要定义一个通用的工厂方法,因为所有创建的具体产品对象都是其他子类对象
  3. ConcreateProduct(具体产品角色):简单工厂的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例,每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法。

代码示例:

// 系列产品
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;
	}
};

	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来直接创建产品对象,而引入了工厂类之后,客户端可以通过工厂类来创建产品,在简单工厂模式中,工厂类提供了一个静态方法供客户端使用

当然上述代码也可用智能指针封装,更好的释放资源:

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

简单工厂模式的简化

为了简化简单工厂模式,我们可以将抽象产品类和工厂类合并,将静态工厂方法移动到抽象产品类中,如图所示:
请添加图片描述

总结

简单工厂优点

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

  1. 一个调用者想创建一个对象,只要知道其名称就可以了;
  2. 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以;
  3. 屏蔽产品的具体实现,调用者只关心产品的接口。
缺点
  1. 每次增加一个产品时,都需要增加一个具体类,并且修改对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
  2. 每当我们想要扩展对象的时候(增加其他类型的对象)就需要在SimpleFactory类中添加代码,增加switch后面的case选项。这样一来,就需要修改源代码。灵活性非常的差,违反了开闭原则!

基于上面的问题,就有了工厂方法

工厂方法

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

具体产品和抽象产品代码不变,接下里是工厂方法的实现:

// 基类(包含纯虚函数,不能实例化对象)
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工厂里面。这才是现实的逻辑,另外,工厂类太多,会不好维护。

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

抽象工厂

有关联关系的,属于一个产品簇的所有产品创建的接口函数,放在一个抽象工厂里面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;
}

其实抽象工厂跟工厂方法比起来,改动就是增加了相关的系列产品后,把产品的创建都放在工厂里,提供多个产品创建的抽象接口,在一个工厂内可以生产多个产品,而非一个产品一个工厂,这样也更加贴近现实社会的逻辑。

抽象工厂其实还存在一个问题:
当一个汽车厂商的一条业务是其他工厂没有的,那么在抽象工厂中添加了这条业务后,其他厂商的工厂方法都必须重写这个业务方法,否则就会变成抽象类,无法实例化。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创建型模式2——工厂模式(简单工厂、工厂方法、抽象工厂) 的相关文章

  • Spring源码学习之BeanDefinition源码解析

    本文作者 磊叔 GLMapper本文链接 https juejin cn post 6844903553820000269 Bean的定义主要由BeanDefinition来描述的 作为Spring中用于包装Bean的数据结构 今天就来看看
  • 行为型模式-策略模式

    package per mjn pattern strategy 抽象策略类 public interface Strategy void show package per mjn pattern strategy 具体策略类 用来封装算法
  • 设计模式之(三)---工厂方法模式

    女娲补天的故事大家都听过吧 这个故事是说 女娲在补了天后 下到凡间一看 哇塞 风景太优美了 天空是湛 蓝的 水是清澈的 空气是清新的 太美丽了 然后就待时间长了就有点寂寞了 没有动物 这些看的到 都是静态的东西呀 怎么办 别忘了是神仙呀 没
  • C++ 装饰器模式

    什么是装饰器模式 装饰器模式是一种结构型设计模式 实现了在不改变现有对象结构的的同时又拓展了新的功能 装饰器本质上是对现有对象的重新包装 同时装饰器又称为封装器 如何理解装饰器模式 以笔记本电脑为例 当我们购买了一台新笔记本电脑 但我们发现
  • Java设计模式:装饰者模式(Decorator Pattern)

    装饰者模式 涉及的重要设计原则 类应该对扩展开放 对修改关闭 装饰者模式定义 装饰者模式动态地将责任附加到对象上 若要扩展功能 装饰者提供了比继承更有弹性的替代方案 UML类图 装饰者模式事例 咖啡店 咖啡种类 1 深焙咖啡 DarkRoa
  • 面向过程和面向对象的语言有哪些,以及优缺点(一篇文章让你理解)

    C语言是面向过程的 而C python java是面向对象的 面向过程的编程思想将一个功能分解为一 个一个小的步骤 我们通过完成一个一 个的小的步骤来完成一个程序 优点 这种编程方式 符合我们人类的思维 编写起来相对比较简单 缺点 但是这种
  • java需会(转载)

    一 基础篇 1 1 Java基础 面向对象的特征 继承 封装和多态 final finally finalize 的区别 Exception Error 运行时异常与一般异常有何异同 请写出5种常见到的runtime exception i
  • Java 多线程模式 —— Guarded Suspension 模式

    Part1Guarded Suspension 模式的介绍 我们只从字面上看 Guarded Suspension 是受保护暂停的意思 1Guarded Suspension 模式 在实际的并发编程中 Guarded Suspension
  • 设计模式 -- 工厂模式(Factory Pattern)

    简单工厂模式 Simple Factory Pattern 根据传入的参数决定实例化哪个对象 优点 不直接在客户端创建具体产品的实例 降低了耦合性 缺点 违反了开闭原则 对扩展开放 对修改关闭 不容易形成高内聚松耦合结构 每当我们增加一种产
  • 单例模式的八种写法比较

    单例模式是最常用到的设计模式之一 熟悉设计模式的朋友对单例模式都不会陌生 一般介绍单例模式的书籍都会提到 饿汉式 和 懒汉式 这两种实现方式 但是除了这两种方式 本文还会介绍其他几种实现单例的方式 让我们来一起看看吧 简介 单例模式是一种常
  • java-IO流(5)-IO流中的设计模式(装饰器模式和适配器模式)的介绍

    目录 1装饰器模式 1 1定义 1 2代码实现 1 3装饰器特点 1 4装饰器在IO流中的使用 2配适器模式 2 1Adapter适配器 2 2代码实例 2 3适配器特点 2 4适配器优缺点 2 5适配器在IO中的使用 3装饰器与适配器异同
  • Java设计模式之装饰者设计模式Decorator Pattern

    目录 一 基本概念 二 结构 1 图示 三 案例演示 被装饰对象的基类 一个接口 有cost 和description 两个抽象方法 具体被装饰的对象 实现上面这个接口 装饰者抽象类 基类 实现drink接口 具体的装饰者类 糖 具体装饰者
  • JavaScript设计模式-02-单例模式

    Javascript 设计模式 02 单例模式 简介 单例就是保证一个类只有一个实例 实现的方法一般是先判断实例是否存在 如果存在直接返回 如果不存在就创建了再返回 确保了一个类只有一个实例对象 在JavaScript里 单例作为一个命名空
  • Java监听器与观察者模式

    Java监听器与观察者模式 Java中的监听器 Listener 和观察者模式 Observer Pattern 都是用于处理对象间的事件通知和响应的设计模式 它们的目的是在对象之间建立一种松散的耦合 使得一个对象的状态变化可以通知到其他对
  • 设计模式—迭代器模式解析

    本文参考学习了 图解设计模式 中的代码实现和原理解释 迭代器模式 简介 Iterator 模式用于在数据集合中按照顺序遍历集合 就类似于我们的循环 一个个去遍历一个集合中的所有元素 示例代码 首先我们思考一个书本和书架的关系 显然 书架可以
  • 在AI技术的无情侵袭下,学学Java的23种设计模式还是非常有必要的

    目前国内80 程序员的主要工作是调用组合api实现各种业务需求 在顶层架构师设定好的框架下 做着重复且无聊的编码工作 如果未来ai被广泛应用 那么被替代的风险是很高的 比较扎心的是 其实目前用ai生成片段代码已经是各个公司比较普遍的做法了
  • 谁能想到Java多线程设计模式竟然能被图解,大佬就是大佬,太牛了

    设计模式 Design pattern 代表了最佳的实践 通常被有经验的面向对象的软件开发人员所采用 设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案 这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的
  • 设计模式(三)-结构型模式(4)-组合模式

    一 为何需要组合模式 Composite 在代码设计中 有种情况是对象之间存在层次关系 即对象之间会存在父结点和子结点的关系 比如在文件管理系统中 所有文件和文件夹形成树状结构 文件夹目录里存在子文件夹和文件 文件夹属于枝结点 文件属于叶结
  • C++设计模式 #3策略模式(Strategy Method)

    动机 在软件构建过程中 某些对象使用的的算法可能多种多样 经常改变 如果将这些算法都写在类中 会使得类变得异常复杂 而且有时候支持不频繁使用的算法也是性能负担 如何在运行时根据需求透明地更改对象的算法 将算法和对象本身解耦 从而避免上述问题
  • 【设计模式之美】理论一:怎么才算是单一原则、如何取舍单一原则

    文章目录 一 如何判断类的职责是否足够单一 二 类的职责是否设计得越单一越好 开始学习一些经典的设计原则 其中包括 SOLID KISS YAGNI DRY LOD 等 本文主要学习单一职责原则的相关内容 单一职责原则的定义 一个类只负责完

随机推荐