JS设计模式之“神奇的魔术师” - 简单工厂模式

引言
在JavaScript开发中,我们经常需要创建和管理各种对象,而简单工厂模式就是一种最简单的用来创建对象的设计模式。
简单工厂模式通过一个工厂类来创建相似的对象,而无需直接使用具体类来实例化对象。这样可以将对象的创建过程与使用过程分离,提供了更好的灵活性和可维护性。
在本篇文章中,我将为您讲解以下内容:
-
什么是简单工厂模式?它的基本思想和原理是什么?
-
如何在JavaScript中使用简单工厂模式?
-
简单工厂模式的优点和缺点是什么?
-
真实场景下的案例分析和应用实践。
一. 什么是简单工厂模式
简单工厂模式(Simple Factory):又叫静态工厂方法,由一个工厂对象决定创建某一种产品对象类的实例,主要用来创建同一类对象。
JavaScript 简单工厂模式是一种编程设计模式,用于创建对象。它通过提供一个简单的工厂函数来封装对象的创建过程,以避免直接使用构造函数或复杂的创建逻辑。

简单工厂模式的基本思想是,根据输入参数的不同,返回不同类的实例。这样可以隐藏对象的创建细节,并将 客户端 与具体的类解耦。
简单工厂模式在一些场景下非常有用,例如当需要根据条件动态创建对象或者创建对象过程比较复杂时。它可以简化客户端的代码,提高代码的可维护性和可扩展性。
二. 实现简单工厂模式的几种方式
简单工厂模式有几种实现方式,以下是常见的几种:

动物类工厂
模拟场景: 以动物类工厂AnimalFactory为例,下面将使用三种不同的方法来进行实践,使用AnimalFactory分别创建了 dog 和 cat 两个动物对象,最后会分别调用了它们的 sound 方法。
1. 静态工厂方法:
这是最常见的实现方式,静态工厂方法是一种在类上定义的方法,用于创建和返回对象实例。使用静态工厂方法可以将对象的创建逻辑封装在类内部,使得客户端只需通过调用方法即可获取到所需的对象。
// 定义一个工厂类
class AnimalFactory {// 静态工厂方法,根据类型创建不同的动物对象static createAnimal(type) {if (type === 'dog') {return new Dog();} else if (type === 'cat') {return new Cat();} else {throw new Error('Invalid type: ' + type);}}
}// 定义动物类
class Dog {sound() {console.log('Woof!');}
}class Cat {sound() {console.log('Meow!');}
}// 使用工厂方法创建对象
const dog = AnimalFactory.createAnimal('dog');
const cat = AnimalFactory.createAnimal('cat');dog.sound(); // 输出: Woof!
cat.sound(); // 输出: Meow!
在上面的代码中,我们首先定义了一个工厂类 AnimalFactory,其中包含一个静态方法 createAnimal,根据传入的类型参数,创建并返回不同类型的动物对象。
接着,我们定义了 Dog 和 Cat 两个具体的动物类,它们都实现了 sound 方法。
最后,我们使用工厂方法 AnimalFactory.createAnimal 分别创建了 dog 和 cat 两个动物对象,并调用了它们的 sound 方法。
2. 实例化工厂对象:
将工厂函数定义为一个实例对象的方法,在创建工厂对象的时候传入构造函数,并通过调用实例方法来创建对象。
// 定义一个工厂类
class AnimalFactory {// 根据类型创建不同的动物对象createAnimal(type) {if (type === 'dog') {return new Dog();} else if (type === 'cat') {return new Cat();} else {throw new Error('Invalid type: ' + type);}}
}// 定义动物类
class Dog {sound() {console.log('Woof!');}
}class Cat {sound() {console.log('Meow!');}
}// 实例化工厂对象
const factory = new AnimalFactory();// 使用工厂对象创建对象
const dog = factory.createAnimal('dog');
const cat = factory.createAnimal('cat');dog.sound(); // 输出: Woof!
cat.sound(); // 输出: Meow!
在上面的代码中,我们定义了一个 AnimalFactory 工厂类,其中包含一个 createAnimal 方法。与之前不同的是,这次是通过实例化工厂对象的方式来使用工厂方法。
接着,我们定义了 Dog 和 Cat 两个具体的动物类,它们都实现了 sound 方法。
然后,我们实例化了一个 AnimalFactory 对象,并使用 factory.createAnimal 方法分别创建了 dog 和 cat 两个动物对象,并调用了它们的 sound 方法。
使用实例化工厂对象的方式实现简单工厂模式,与使用静态工厂方法的实现相比,更加灵活,可以在工厂对象中保存状态,进行更复杂的对象创建逻辑。
3. 使用闭包封装工厂函数:
闭包是一种函数和其相关引用环境(词法环境)的组合。使用闭包可以实现封装和私有变量等特性。利用闭包将工厂函数封装起来,返回一个创建对象的函数,通过调用这个函数来创建对象。
// 封装工厂函数
const AnimalFactory = (function() {// 私有变量和方法const animals = {dog: Dog,cat: Cat};// 返回工厂函数return function(type) {if (typeof animals[type] !== 'function') {throw new Error('Invalid type: ' + type);}return new animals[type]();};
})();// 定义动物类
class Dog {sound() {console.log('Woof!');}
}class Cat {sound() {console.log('Meow!');}
}// 使用闭包封装的工厂函数创建对象
const dog = AnimalFactory('dog');
const cat = AnimalFactory('cat');dog.sound(); // 输出: Woof!
cat.sound(); // 输出: Meow!
在上面的代码中,我们使用闭包将工厂函数封装在一个立即执行函数表达式 (IIFE) 中。这样做的好处是可以创建一个私有的变量 animals 来存储不同类型动物的构造函数。通过这种方式,我们可以在工厂函数内部访问 animals 对象,并根据传入的类型来创建对应的对象。
然后,我们定义了 Dog 和 Cat 两个具体的动物类,它们都实现了 sound 方法。
最后,我们使用封装在闭包中的工厂函数 AnimalFactory 创建了 dog 和 cat 两个动物对象,并调用了它们的 sound 方法。
通过使用闭包封装工厂函数,我们可以将工厂函数的内部状态和逻辑隐藏起来,只暴露一个公共的接口。这样可以实现更好的封装和信息隐藏,避免对外暴露不必要的细节。
总结:以上三种方式都是常见的简单工厂模式的实现方式,每种方式都有各自的点和适用场景,它们在应用方面也有一些区别,可以根据具体需选择合适的方式来实现简单工厂模式。
三. 类与简单工厂模式
简单工厂模式是一种创建对象的设计模式,而类是面向对象编程的基本概念。它们之间有以下异同点:
1. 异同点:
-
创建对象方式:简单工厂模式使用工厂函数来创建对象,根据输入参数的不同返回不同类的实例;而类则是通过定义构造函数和使用
new关键字来创建对象。 -
继承关系:简单工厂模式的工厂函数负责创建不同类的实例,这些类可以是没有继承关系的独立类;而类是通过继承实现类与类之间的层次关系。
-
类型判断:使用简单工厂模式创建的对象可以通过参数类型进行判断;而类可以通过
of运算符来判断对象的类型。 -
对象的创建逻辑:简单工厂模式将对象的创建逻辑封装在工厂函数中,客户端只需调用工厂函数,而不关心具体的创建过程;而类的创建逻辑则是在构造函数中。
2. 案例分析:

模拟场景:
假设我们需要创建不同类型的汽车对象,其中包括小轿车(sedan)和越野车(SUV)。使用简单工厂模式和类的方式可以如下实现:
使用类:
class Car {constructor(type) {this.type = type;}
}class SedanCar extends Car {constructor() {super("sedan");}
}
class SUVCar extends Car {constructor() {super("SUV");}
}var myCar = new SedanCar();
console.log(myCar.type); // 输出: "sedan"var anotherCar = new SUVCar();
console.log(anotherCar.type); //: "SUV"
使用简单工厂模式:
function CarFactory() {}CarFactory.createCar = function(type) {if (type === "sedan") {return new SedanCar();} else if (type === "SUV") {return new SUVCar();} else {throw new Error("Invalid car type.");}
}function SedanCar() {this.type = "sedan";
}function SUVCar() {this.type = "SUV";
}var myCar = CarFactory.createCar("sedan");
console.log(myCar.type); // 输出: "sedan"var anotherCar = CarFactory.createCar("SUV");
console.log(anotherCar.type); // 输出: "SUV"
以上两种方式都能所需的汽车对象,其中简工厂模式将对象创建逻辑封装在 CarFactory 工厂函数中,类的方式则通过继承和构造函数来创建不同类型的汽车对象。
四. 简单工厂模式的优缺点
以上我们了解到简单工厂模式是一种创建对象的设计模式,它具有以下优点和缺点:
1. 优点:
-
封装了对象的创建逻辑,客户端只需通过工厂函数来创建对象,而不需要了解具体的创建过程,降低了客户端的复杂性和依赖性。
-
可以集中管理对象的创建逻辑,方便统一修改和维护。如果需要新增或修改对象的创建方式只需修改工厂函数中的代码即可,而不需要修改客户端的代码。
-
实现了对象创建解耦,客户端与工厂函数进行交互,不直接依赖具体的类,增加了灵活性和可扩展性。
2. 缺点:
-
违背了开闭原则,需要新增一种类型的对象时,必须修改工厂函数的代码,增加了厂函数的维护成本。
-
创建对象的逻辑集中工厂函数中,导致工厂函数的代码可能过于复杂,不易维护和扩展。
-
不符合单一职责原则,一个工厂函数负责创建多种类型的对象,当对象创建逻辑复杂时,工厂函数会变得臃肿。
结语
相信通过本文对简单工厂模式的学习,你一定对这个设计模式有了更深入的了解。
简单工厂模式是一种常用的创建型设计模式,在JavaScript中广泛应用于对象的创建和管理。它通过一个工厂类来将对象的创建过程与使用过程分离,提供了更好的灵活性和可维护性。
在使用简单工厂模式时,我们可以通过工厂类创建不同类型的对象,而无需直接使用具体类来实例化对象。这样可以避免在客户端代码中直接暴露具体类,提高了代码的封装性和可扩展性。
同时,简单工厂模式也有一些限制,例如:难以支持复杂的对象创建逻辑或创建过程可能会非常复杂等。简单工厂模式适合创建对象较简单,类型不频繁变化的场景。如果需要创建的对象较复杂,或者对象的类型经常变化,适合使用其他创建对象的设计模,如工厂方法模式或抽象工厂模式,我将会在后面的文章继续讲解。在实际应用中,我们需要根据具体的场景和需求,选择合适的设计模式。
希望通过本文的介绍,您能够对JavaScript简单工厂模式有了更清晰的认识,并能够在实际项目中灵活应用。

相关文章:
JS设计模式之“神奇的魔术师” - 简单工厂模式
引言 在JavaScript开发中,我们经常需要创建和管理各种对象,而简单工厂模式就是一种最简单的用来创建对象的设计模式。 简单工厂模式通过一个工厂类来创建相似的对象,而无需直接使用具体类来实例化对象。这样可以将对象的创建过程与使用过程…...
【河北航空-注册安全分析报告-无验证方式导致安全隐患】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 1. 暴力破解密码,造成用户信息泄露 2. 短信盗刷的安全问题,影响业务及导致用户投诉 3. 带来经济损失,尤其是后付费客户,风险巨大,造…...
亚信安慧AntDB-T数据库内核之MVCC机制
本文主要介绍AntDB数据库内核中的一个很重要的机制——MVCC机制。 MVCC简介 MVCC(多版本并发控制)是AntDB数据库中实现事务隔离级别的一种机制。它允许多个事务同时对数据进行读写和修改操作,而不会相互干扰。在MVCC中,每个数据…...
【python】socket 入门以及多线程tcp链接
Socket 入门 及 多线程tcp链接 网络基础知识三要素 Socket是套接字的意思,是网络编程的核心对象,通信两端都独有自己的Socket对象, 数据在两个Socket之间通过 字节流(TCP协议) 或者 数据报包(UDP协议)的形式进行传输. 本文主要针对tcp流程进行讲解 socket-tcp流程图 1.创建服…...
【ZYNQ MPSoC开发】lwIP TCP发送用于数据缓存的软件FIFO设计
设计背景 任务是在ZYNQ的PS上使用裸机运行lwIP协议栈使用TCP把PL端通过AXI DMA传来的将近100K采样率的ADC数据发送出去,但由于数据带宽很大,有853.3mbps,所以在每一次AXI DMA简单传输结束后,lwIP未必有足够的发送buffer立即把数据…...
【TVM 教程】在 Relay 中使用外部库
Apache TVM 是一个端到端的深度学习编译框架,适用于 CPU、GPU 和各种机器学习加速芯片。更多 TVM 中文文档可访问 → https://tvm.hyper.ai/ 作者:Masahiro Masuda,Truman Tian 本文介绍如何将 cuDNN 或 cuBLAS 等外部库与 Relay 一起使用。…...
2024最新大厂面试:汇川嵌入式面试题及参考答案
目录 结合汇川业务,谈谈你对嵌入式开发的理解。 你使用过哪些芯片?请介绍它们的架构,例如 CORTEX-M3。 请描述项目的软件架构及其难点。 请介绍 SPI 的驱动和时序,包括 CS 拉低后到 CLK 第一个跳变沿的时间。同时,也请简要介绍数据链路层的相关知识。 栈溢出的原理是…...
tcp 流量控制
TCP流量控制是TCP/IP协议中用于控制发送方和接收方之间数据传输速率的一种机制,以防止网络拥塞和确保网络资源的有效利用。流量控制主要通过调整TCP窗口大小来实现,确保发送方不会发送超出接收方处理能力的数据量。以下是TCP流量控制的关键概念和工作原理…...
linux离线安装nacos
1、打开 Nacos-GitHub ,点击 Release 可以看到 Nacos 的各版本跟新信息和安装包之类的 点击下载nacos-server-2.4.1.tar.gz,在linux创建nacos文件夹,把下载好的文件上传到nacos文件夹,并通过命令解压:tar -zxvf nacos-server-2.4.…...
云原生 | 在 Kubernetes 中使用 Cilium 替代 Calico 网络插件实践指南!
[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路 ] 0x00 简述介绍 什么是 Cilium? Cilium 是一款开源软件,它基于一种名为eBPF的新的Linux内核技术提供动力,用于透明地保护使用 Docker 和 Kubernetes 等Linux 容器管理平台中部署的应用程序服务之间的网络连接,Ciliu…...
【重学 MySQL】十一、SQL 概述
【重学 MySQL】十一、SQL 概述 SQL 背景知识产生与发展主要特点主要应用SQL语言的发展趋势 SQL 语言排行榜SQL 分类数据查询语言(DQL, Data Query Language)数据操纵语言(DML, Data Manipulation Language)数据定义语言࿰…...
(一)模式识别——基于SVM的道路分割实验(附资源)
写在前面:本报告所有代码公开在附带资源中,无法下载代码资源的伙伴私信留下邮箱,小编24小时内回复 一、实验目的 1、实验目标 学习掌握SVM(Support Vector Machine)算法思想,利用MATLAB的特定工具箱和库函…...
Python | Leetcode Python题解之第391题完美矩形
题目: 题解: class Solution:def isRectangleCover(self, rectangles: List[List[int]]) -> bool:area, minX, minY, maxX, maxY 0, rectangles[0][0], rectangles[0][1], rectangles[0][2], rectangles[0][3]cnt defaultdict(int)for rect in rec…...
Rust模块std::thread
【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust到底值不值得学,之一 -CSDN博客 Rust到底值不值得学,之二-CSDN博客 Rust多线程编程概述-CSDN博客 12.…...
Leetcode Day20 打家劫舍
198 最基础 class Solution:def rob(self, nums: List[int]) -> int:dp1 [0] * len(nums)dp2 [0] * len(nums)# dp1指第i天偷了, dp2指第i天没有偷dp1[0] nums[0]for i in range(1, len(nums)):dp1[i] dp2[i - 1] nums[i]dp2[i] max(dp1[i - 1], dp2[i - 1])return m…...
云计算之数据库
目录 一、RDS产品介绍及排障思路 1.1 云RDS数据库及其特点 1.2 云RDS数据库-规格 1.3 云RDS数据库-存储 1.4 云RDS数据库-安全 1.5 云RDS数据库-整体架构 1.6 RDS常见问题排查 1.6.1 如何解决无法链接RDS实例的问题 1.6.2 RDS实例存储空间使用率高,怎…...
开发软件,什么类型的重要信息的日志要存到数据库表里面
在开发软件时,选择将哪些类型的重要信息日志存储到数据库表里面,主要取决于这些日志的用途、查询需求、性能考虑以及系统架构。以下是一些通常会选择存储到数据库表中的重要信息日志类型: 1. 业务日志: 交易记录:记录…...
websocket和轮询的区别?
问: websocket和轮询的区别? 回答: WebSocket 和定时轮询(每隔几秒发送一次请求)是两种不同的实时通信方法,各有优缺点,适用于不同的场景。以下是它们的主要区别及适用场景: WebSo…...
2024 年全国大学生数学建模竞赛(国赛)浅析
需要完整资料,请关注WX:“小何数模”! (需要完整B、C和E题资料请关注WX:“小何数模”,获取资料链接!) 本次万众瞩目的全国大学生数学建模赛题已正式出炉,无论是赛题难度…...
持续集成与持续部署(CI/CD)的深入探讨
在现代软件开发中,持续集成(CI)和持续部署(CD)已成为不可或缺的实践。这些方法旨在加快软件交付的速度,同时提高软件的质量和稳定性。通过CI/CD,开发团队可以频繁地将代码更改集成到主分支&…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
【Linux系统】Linux环境变量:系统配置的隐形指挥官
。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量:setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...
【WebSocket】SpringBoot项目中使用WebSocket
1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖,添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...
一些实用的chrome扩展0x01
简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序,无论是测试应用程序、搜寻漏洞还是收集情报,它们都能提升工作流程。 FoxyProxy 代理管理工具,此扩展简化了使用代理(如 Burp…...
Linux安全加固:从攻防视角构建系统免疫
Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...
