设计模式:简单工厂模式、工厂方法模式、抽象工厂模式

简单工厂模式、工厂方法模式、抽象工厂模式

  • 1. 为什么需要工厂模式?
  • 2. 简单工厂模式
    • 2.1. 定义
    • 2.2. 代码实现
    • 2.3. 优点
    • 2.4. 缺点
    • 2.5. 适用场景
  • 3. 工厂方法模式
    • 3.1. 有了简单工厂模式为什么还需要有工厂方法模式?
    • 3.2. 定义
    • 3.3. 代码实现
    • 3.4. 主要优点
    • 3.5. 主要缺点
    • 3.6. 适用场景
  • 4. 抽象工厂模式
    • 4.1. 产品等级结构与产品族
    • 4.2. 为什么需要抽象工厂模式?
    • 4.3. 定义
    • 4.4. 代码实现
    • 4.5. 主要优点
    • 4.6. 主要缺点
    • 4.7. 使用场景
  • 5. 总结

1. 为什么需要工厂模式?

工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的方式,将对象的实例化过程与客户端代码解耦(即创建与使用解耦)。工厂模式的主要目的是提供一种灵活的对象创建机制,以便根据需求创建不同类型的对象。

以下是一些需要使用工厂模式的情况:

  1. 封装对象的创建逻辑:当对象的创建过程比较复杂,涉及到多个步骤或依赖关系时,可以使用工厂模式将对象的创建逻辑封装到工厂类中。这样客户端代码只需要与工厂类进行交互,而无需了解具体的创建细节。

  2. 实现对象的解耦:工厂模式可以将对象的实例化过程与客户端代码解耦,使得客户端代码不需要直接依赖具体的类。客户端只需要通过工厂类来获取所需的对象,使得代码更加灵活和可维护。

  3. 统一管理对象的创建:通过工厂模式,可以将对象的创建集中在工厂类中进行管理,避免了代码中多处重复的对象创建代码。这样可以更好地控制对象的创建逻辑,提高代码的复用性和可维护性。

  4. 实现产品族的创建:工厂模式可以用于创建产品族,即一组相关或相互依赖的产品对象。通过定义不同的工厂类来创建不同的产品族,可以使得创建过程更加灵活,同时也符合开闭原则,方便扩展新的产品族。

2. 简单工厂模式

2.1. 定义

简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。

2.2. 代码实现

#include <iostream>
#include <string>// 抽象产品类
class Product {
public:virtual void Use() = 0;
};// 具体产品类 A
class ConcreteProductA : public Product {
public:void Use() override {std::cout << "Using ConcreteProductA" << std::endl;}
};// 具体产品类 B
class ConcreteProductB : public Product {
public:void Use() override {std::cout << "Using ConcreteProductB" << std::endl;}
};// 简单工厂类
class SimpleFactory {
public:// 根据传入的参数创建不同的产品对象static Product* CreateProduct(const std::string& productType) {if (productType == "A") {return new ConcreteProductA();} else if (productType == "B") {return new ConcreteProductB();}return nullptr;}
};int main() {// 使用简单工厂创建产品对象Product* productA = SimpleFactory::CreateProduct("A");if (productA) {productA->Use();delete productA;}Product* productB = SimpleFactory::CreateProduct("B");if (productB) {productB->Use();delete productB;}return 0;
}

2.3. 优点

  1. 工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例。客户端可以免除直接创建产品对象的职责,而仅仅“消费”产品。简单工厂模式实现了对象创建和使用的分离。
  2. 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可。对于一些复杂的类名,通过简单工厂模式可以在一定程度减少使用者的记忆量。
  3. 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

2.4. 缺点

  1. 由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响。
  2. 使用简单工厂模式势必会增加系统中类的个数(引入了新的工厂类),增加了系统的复杂度和理解难度。
  3. 系统扩展困难。一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
  4. 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

2.5. 适用场景

  1. 工厂类负责创建的对象比较少。由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
  2. 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。

3. 工厂方法模式

3.1. 有了简单工厂模式为什么还需要有工厂方法模式?

在简单工厂模式中只提供一个工厂类,该工厂类处于对产品类进行实例化的中心位置,它需要知道每个产品对象的创建细节,并决定何时实例化哪一个产品类。简单工厂模式最大的缺点是当有新产品要加入系统中时,必须修改工厂类,需要在其中加入必要的业务逻辑,这违背了开闭原则。此外,在简单工厂模式中,所有的产品都由同一个工厂创建,工厂类职责较重,业务逻辑较为复杂,具体产品与工厂类之间的耦合度高,严重影响了系统的灵活性和扩展性,而工厂方法模式则可以很好地解决这一问题。在工厂方法模式中,不再提供一个统一的工厂类来创建所有的产品对象,而是针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构。工厂方法模式定义如下:

3.2. 定义

工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式(Factory Pattern),又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。工厂方法模式是一种类创建型模式。

3.3. 代码实现

#include <iostream>
#include <string>// 抽象产品类
class Product {
public:virtual void Use() = 0;
};// 具体产品类 A
class ConcreteProductA : public Product {
public:void Use() override {std::cout << "Using ConcreteProductA" << std::endl;}
};// 具体产品类 B
class ConcreteProductB : public Product {
public:void Use() override {std::cout << "Using ConcreteProductB" << std::endl;}
};// 抽象工厂类
class Factory {
public:virtual Product* CreateProduct() = 0;
};// 具体工厂类 A
class ConcreteFactoryA : public Factory {
public:Product* CreateProduct() override {return new ConcreteProductA();}
};// 具体工厂类 B
class ConcreteFactoryB : public Factory {
public:Product* CreateProduct() override {return new ConcreteProductB();}
};int main() {// 使用工厂方法创建产品对象Factory* factoryA = new ConcreteFactoryA();Product* productA = factoryA->CreateProduct();if (productA) {productA->Use();delete productA;}delete factoryA;Factory* factoryB = new ConcreteFactoryB();Product* productB = factoryB->CreateProduct();if (productB) {productB->Use();delete productB;}delete factoryB;return 0;
}

工厂方法模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,同时还弥补了简单工厂模式的不足。工厂方法模式是使用频率最高的设计模式之一,是很多开源框架和API类库的核心模式。

3.4. 主要优点

(1)在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节。用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
(2)基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够让工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,正是因为所有的具体工厂类都具有同一抽象父类。
(3)使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合开闭原则。

3.5. 主要缺点

(1)在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
(2)由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到反射等技术,增加了系统的实现难度

3.6. 适用场景

(1)客户端不知道其所需要的对象的类。在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建,可将具体工厂类的类名存储在配置文件或数据库中。
(2)抽象工厂类通过其子类来指定创建哪个对象。在工厂方法模式中,抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。

4. 抽象工厂模式

工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题。但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。此时,可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产。

4.1. 产品等级结构与产品族

在工厂方法模式中,具体工厂负责生产具体的产品,每个具体工厂对应一种具体产品,工厂方法具有唯一性。一般情况下,一个具体工厂中只有一个或者一组重载的工厂方法。但是,有时希望一个工厂可以提供多个产品对象,而不是单一的产品对象。例如一个电器工厂,它可以生产电视机、电冰箱、空调等多种电器,而不是只生产某一种电器。为了更好地理解抽象工厂模式,这里先引入如下两个概念:(1)产品等级结构。产品等级结构即产品的继承结构,例如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。(2)产品族。在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。例如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中,海尔电视机、海尔电冰箱构成了一个产品族。
在这里插入图片描述

只要指明一个产品所处的产品族以及它所属的等级结构,就可以唯一确定这个产品。

4.2. 为什么需要抽象工厂模式?

当系统所提供的工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时,就可以使用抽象工厂模式。抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形式。抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、更有效率。
在这里插入图片描述
在上图中,每一个具体工厂可以生产属于一个产品族的所有产品,例如海尔工厂生产海尔电视机、海尔冰箱和海尔空调,所生产的产品又位于不同的产品等级结构中。如果使用工厂方法模式,实现上图所示结构需要提供9个具体工厂,而使用抽象工厂模式只需要提供3个具体工厂,极大地减少了系统中类的个数。

4.3. 定义

抽象工厂模式为创建一组对象提供了一种解决方案。与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一族产品。

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。

4.4. 代码实现

#include <iostream>
#include <string>// 抽象产品类 A
class AbstractProductA {
public:virtual void Use() = 0;virtual ~AbstractProductA() {}
};// 具体产品类 A1
class ConcreteProductA1 : public AbstractProductA {
public:void Use() override {std::cout << "Using ConcreteProductA1" << std::endl;}
};// 具体产品类 A2
class ConcreteProductA2 : public AbstractProductA {
public:void Use() override {std::cout << "Using ConcreteProductA2" << std::endl;}
};// 抽象产品类 B
class AbstractProductB {
public:virtual void Use() = 0;virtual ~AbstractProductB() {}
};// 具体产品类 B1
class ConcreteProductB1 : public AbstractProductB {
public:void Use() override {std::cout << "Using ConcreteProductB1" << std::endl;}
};// 具体产品类 B2
class ConcreteProductB2 : public AbstractProductB {
public:void Use() override {std::cout << "Using ConcreteProductB2" << std::endl;}
};// 抽象工厂类
class AbstractFactory {
public:virtual AbstractProductA* CreateProductA() = 0;virtual AbstractProductB* CreateProductB() = 0;virtual ~AbstractFactory() {}
};// 具体工厂类 A
class ConcreteFactoryA : public AbstractFactory {
public:AbstractProductA* CreateProductA() override {return new ConcreteProductA1();}AbstractProductB* CreateProductB() override {return new ConcreteProductB1();}
};// 具体工厂类 B
class ConcreteFactoryB : public AbstractFactory {
public:AbstractProductA* CreateProductA() override {return new ConcreteProductA2();}AbstractProductB* CreateProductB() override {return new ConcreteProductB2();}
};int main() {// 使用抽象工厂创建产品对象AbstractFactory* factoryA = new ConcreteFactoryA();AbstractProductA* productA = factoryA->CreateProductA();AbstractProductB* productB = factoryA->CreateProductB();if (productA) {productA->Use();delete productA;}if (productB) {productB->Use();delete productB;}delete factoryA;AbstractFactory* factoryB = new ConcreteFactoryB();AbstractProductA* productA2 = factoryB->CreateProductA();AbstractProductB* productB2 = factoryB->CreateProductB();if (productA2) {productA2->Use();delete productA2;}if (productB2) {productB2->Use();delete productB2;}delete factoryB;return 0;
}

抽象工厂模式是工厂方法模式的进一步延伸,由于它提供了功能更为强大的工厂类并且具备较好的可扩展性,在软件开发中得以广泛应用,尤其是在一些框架和API类库的设计中。

4.5. 主要优点

(1)抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了在抽象工厂中声明的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。
(2)当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
(3)增加新的产品族很方便,无须修改已有系统,符合开闭原则。

4.6. 主要缺点

增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了开闭原则。

4.7. 使用场景

(1)一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是很重要的,用户无须关心对象的创建过程,将对象的创建和使用解耦。
(2)系统中有多于一个的产品族,而每次只使用其中某一个产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。
(3)属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。同一个产品族中的产品可以是没有任何关系的对象,但是它们都具有一些共同的约束。例如同一操作系统下的按钮和文本框,按钮与文本框之间没有直接关系,但它们都是属于某一操作系统的,此时具有一个共同的约束条件:操作系统的类型。
(4)产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。

5. 总结

简单工厂模式适用于创建对象较少且变化不频繁的情况,工厂方法模式适用于创建对象较多且需要灵活扩展的情况,而抽象工厂模式适用于创建一组相关对象的情况。

所有的工厂模式都强调一点:两个类A和B之间的关系应该仅仅是A创建B或是A使用B,而不能两种关系都有。将对象的创建和使用分离,也使得系统更加符合单一职责原则,有利于对功能的复用和系统的维护。此外,将对象的创建和使用分离还有一个好处:防止用来实例化一个类的数据和代码在多个类中到处都是,可以将有关创建的知识搬移到一个工厂类中。因为有时候创建一个对象不只是简单调用其构造函数,还需要设置一些参数,可能还需要配置环境。如果将这些代码散落在每一个创建对象的客户类中,势必会出现代码重复、创建蔓延的问题,而这些客户类其实无须承担对象的创建工作,只需使用已创建好的对象就可以了。此时,可以引入工厂类来封装对象的创建逻辑和客户代码的实例化/配置选项。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/316080.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

内存管理机制

内存管理机制与内存映射相关。 一、C与C 之所以将C与C放在一起是因为C是C的超集&#xff1b; 但是C是面向过程语言&#xff0c;C是面向对象的语言&#xff1b; C与C都可以使用malloc、calloc、realloc来申请内存空间&#xff1b; 其中void* malloc(size_t size)是在内存的动态…

引导过程的解析以及教程za

bios加电自检------mbr--------grub-------加载内核文件------启动第一个进程 bios的主要作用&#xff1a;检测硬件是否正常&#xff0c;然后根据bios中的启动项设置&#xff0c;去找内核文件 boot开机启动项顺序&#xff0c;你可以把内核文件放在何处&#xff1f; 1.硬盘 …

STL map容器与pair类模板(解决扫雷问题)

CSTL之Map容器 - 数据结构教程 - C语言网 (dotcpp.com)https://www.dotcpp.com/course/118CSTL之Pair类模板 - 数据结构教程 - C语言网 (dotcpp.com)https://www.dotcpp.com/course/119 刷到一个扫雷的题目&#xff0c;之前没有玩怎么过扫雷&#xff0c;于是我就去玩了玩…

使用Apache Commons SCXML实现状态机管理

第1章&#xff1a;引言 大家好&#xff0c;我是小黑&#xff0c;咱们程序员在开发过程中&#xff0c;经常会遇到需要管理不同状态和状态之间转换的场景。比如&#xff0c;一个在线购物的订单&#xff0c;它可能有“新建订单”、“已支付”、“配送中”、“已完成”等状态。在这…

数脉观察二丨 详解CroPoolv2.0锁仓收益机制 文末附锁仓教程

1月1日元旦佳节期间&#xff0c;CyberVein基金会支持打造的CroPoolv2.0最新版本正式上线&#xff0c;获得了圈内媒体和知名KOL多方的关注&#xff0c;在Staking领域掀起了热议&#xff0c;用户可以前往CroPool.net进行锁仓体验。 CroPool v2.0新增“锁仓”功能板块&#xff0c…

Element-ui自定义input框非空校验

1、vue自定义非空指令&#xff1a; main.js中自定义非空指令 当input框或下拉框中数据更新时&#xff0c;触发校验 Vue.directive(isEmpty,{update:function(el,binding,vnode){if(vnode.componentInstance.value""){el.classList.add("is-required");}e…

springboot实现ChatGPT式调用(一次调用,持续返回)

下边实现了一个持续返回100以内随机数的接口&#xff0c;在接口超时之前会每隔1秒返回一个随机数 GetMapping(value "/getRandomNum", produces MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter getRandomNum() {SseEmitter emitter new SseEmitter();Th…

微服务-OpenFeign-工程案例

Ribbon 前置知识 是NetFlix的开源项目&#xff0c;主要来提供关于客户端的负载均衡能力。从多个服务提供方&#xff0c;选取一个节点发起调用。 Feign:NetFlix,SpringCloud 的第一代LB&#xff08;负载均衡&#xff09;客户端工具包。 OpenFeign:SpringCloud自研&#xff0c…

CMake支持的编译平台和IDE

文章目录 简介支持的IDEVisual Studio支持示例 其他编译器和生成器支持MinGW示例 IDE集成Eclipse示例 实验性和特殊平台支持总结 简介 CMake是一个非常强大的跨平台自动化构建工具&#xff0c;它支持生成多种类型的项目文件&#xff0c;覆盖了广泛的开发环境和编译器。在这篇博…

OpenHarmony之HDF驱动框架

概述 HDF&#xff08;Hardware Driver Foundation&#xff09;驱动框架&#xff0c;为驱动开发者提供驱动框架能力&#xff0c;包括驱动加载、驱动服务管理、驱动消息机制和配置管理。并以组件化驱动模型作为核心设计思路&#xff0c;让驱动开发和部署更加规范&#xff0c;旨在…

LOG滤波器原理探究---计算机视觉和特征检测

先来看几个滤波器公式&#xff1a; 高斯滤波器&#xff1a; G ( x , y ; σ ) 1 2 π σ 2 e − x 2 y 2 2 σ 2 G(x,y;\sigma) \frac{1}{2 \pi \sigma^2} e^{-\frac{x^2 y^2}{2\sigma^2}} G(x,y;σ)2πσ21​e−2σ2x2y2​ 图像的二阶导数&#xff1a; ∇ 2 f ∂ 2 f ∂…

ARM NEON 指令

NEON指令 按照操作数类型可以分为正常指令、宽指令、窄指令、饱和指令、长指令。 正常指令&#xff1a;生成大小相同且类型通常与操作数向量相同到结果向量。长指令&#xff1a;对双字向量操作数执行运算&#xff0c;生产四字向量到结果。所生成的元素一般是操作数元素宽度到…