【设计模式】01- 一文理解常用设计模式-“创建型模式”篇
一、前言
最近在复习设计模式,撰写、整理了内容和代码片段,和大家一起交流学习。
设计模式是软件设计中常见问题的典型解决方案。
修改记录
| 更新内容 | 更新时间 |
|---|---|
| 第一版 | 250212 |
| 更新了对文章中的模式代码示范的解释 | 250214 |
二、模式分类
模式可以根据其意图或目的来分类。常见的设计模式包括:
创建型模式提供创建对象的机制, 增加已有代码的灵活性和可复用性;
结构型模式介绍如何将对象和类组装成较大的结构, 并同时保持结构的灵活和高效;
行为型模式负责对象间的高效沟通和职责委派;
本篇文章介绍创建型模式,后续会更新其他两类设计模式。
三、创建型模式概述
创建型模式主要用于对象的创建过程,它隐藏了对象的创建逻辑,使得代码更具灵活性和可维护性。
四、常见创建型模式(配合代码)
1、单例模式(Singleton Pattern):
确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。
// 单例模式示例
const Singleton = (function () {let instance;function createInstance() {const object = new Object({ name: 'Singleton Object' });return object;}return {getInstance: function () {if (!instance) {instance = createInstance();}return instance;}};}());// 使用示例const instance1 = Singleton.getInstance();const instance2 = Singleton.getInstance();console.log(instance1 === instance2); // 输出: true
代码分析
- 立即执行函数(IIFE):
- 代码使用了一个立即执行函数
(function () { ... }()),这样可以创建一个独立的作用域,避免变量和函数泄露到全局作用域。instance变量:
- 在立即执行函数内部声明了一个变量
instance,初始值为undefined。这个变量用于存储单例对象的实例。createInstance函数:
- 该函数用于创建单例对象的实例。它使用
new Object()创建一个新对象,并传入一个包含name属性的对象字面量{ name: 'Singleton Object' },最后返回这个新对象。- 返回对象:
- 立即执行函数返回一个包含
getInstance方法的对象。这个对象就是外部可以访问的接口。getInstance方法:
- 该方法是获取单例对象实例的唯一途径。
- 首先检查
instance是否为undefined(即是否已经创建了实例)。如果instance为undefined,则调用createInstance函数创建一个新的实例,并将其赋值给instance。- 最后返回
instance。这样,无论调用多少次getInstance方法,只要instance已经被创建,就会一直返回同一个实例。
代码运行结果
- 调用
Singleton.getInstance()方法两次,分别将返回的实例存储在instance1和instance2中。- 使用
===比较instance1和instance2是否为同一个对象。由于单例模式确保只有一个实例存在,所以instance1和instance2是同一个对象,比较结果为true,并将结果打印到控制台。

2、工厂模式(Factory Pattern):
定义一个创建对象的接口,让子类决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类。
简单理解:工厂模式就像一个工厂,根据不同的需求生产不同的产品。你只需要告诉工厂你需要什么,工厂就会帮你创建出来。
// 工厂模式示例
function CarFactory() {this.createCar = function (type) {let car;if (type === 'sedan') {car = new Sedan();} else if (type === 'suv') {car = new SUV();}car.drive = function () {console.log(`Driving a ${this.constructor.name}`);};return car;};
}
//createCar 方法:
//该方法接收一个 type 参数,用于指定要创建的汽车类型。
//根据 type 的值,使用 if-else 语句来决定创建哪种类型的汽车对象。如果 type 为 'sedan',则创建一个 Sedan 对象;如果 type 为 'suv',则创建一个 SUV 对象。
//为创建的汽车对象添加一个 drive 方法,该方法会在控制台打印出正在驾驶的汽车类型。这里使用 this.constructor.name 来获取汽车对象的构造函数名,从而得到汽车的类型。
//最后返回创建好的汽车对象。function Sedan() {this.type = 'Sedan';
}
//这是一个简单的构造函数,用于创建轿车对象。在创建 Sedan 对象时,会给对象添加一个 type 属性,值为 'Sedan'。function SUV() {this.type = 'SUV';
}
//意思同上// 使用示例
const factory = new CarFactory();
const sedan = factory.createCar('sedan');
const suv = factory.createCar('suv');
sedan.drive(); // 输出: Driving a Sedan
suv.drive(); // 输出: Driving a SUV
代码运行结果
- 创建一个
CarFactory类的实例factory。- 调用
factory.createCar('sedan')方法创建一个轿车对象,并将其赋值给sedan。- 调用
factory.createCar('suv')方法创建一个 SUV 对象,并将其赋值给suv。- 分别调用
sedan.drive()和suv.drive()方法,会在控制台输出相应的驾驶信息,表明成功创建并使用了不同类型的汽车对象。

3、抽象工厂模式(Abstract Factory Pattern):
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
简单理解:就像一个超级工厂,能生产不同品牌的汽车系列产品。
// 抽象工厂模式示例
// 抽象工厂
function AbstractCarFactory() {this.createEngine = function () {throw new Error('This method must be overridden!');};this.createWheel = function () {throw new Error('This method must be overridden!');};
}
//功能:抽象工厂定义了创建发动机和车轮的抽象方法。由于这是抽象工厂,这些方法并没有具体实现,而是抛出一个错误,提醒具体工厂必须重写这些方法。
//作用:为具体工厂提供了一个统一的接口,确保所有具体工厂都实现了创建发动机和车轮的功能。// 具体工厂:丰田工厂
function ToyotaFactory() {AbstractCarFactory.call(this);this.createEngine = function () {return new ToyotaEngine();};this.createWheel = function () {return new ToyotaWheel();};
}
//继承:使用 AbstractCarFactory.call(this) 继承了抽象工厂的属性和方法。
//方法实现:重写了 createEngine 方法,返回一个 ToyotaEngine 实例;重写了 createWheel 方法,返回一个 ToyotaWheel 实例。
// 具体工厂:本田工厂
function HondaFactory() {AbstractCarFactory.call(this);this.createEngine = function () {return new HondaEngine();};this.createWheel = function () {return new HondaWheel();};
}
//继承:同样继承了抽象工厂的属性和方法。
//方法实现:重写了 createEngine 方法,返回一个 HondaEngine 实例;重写了 createWheel 方法,返回一个 HondaWheel 实例。// 丰田发动机
function ToyotaEngine() {this.start = function () {console.log('Toyota engine started');};
}
//功能:表示丰田发动机,有一个 start 方法,用于启动发动机并在控制台输出相应信息。// 丰田车轮
function ToyotaWheel() {this.rotate = function () {console.log('Toyota wheel rotating');//功能:表示丰田车轮,有一个 rotate 方法,用于模拟车轮转动并在控制台输出相应信息。};
}
// 本田发动机
function HondaEngine() {this.start = function () {console.log('Honda engine started');};
}
//功能:表示本田发动机,有一个 start 方法,用于启动发动机并在控制台输出相应信息。
// 本田车轮
function HondaWheel() {this.rotate = function () {console.log('Honda wheel rotating');};
}
//功能:表示本田车轮,有一个 rotate 方法,用于模拟车轮转动并在控制台输出相应信息。// 使用示例
const toyotaFactory = new ToyotaFactory();
const toyotaEngine = toyotaFactory.createEngine();
const toyotaWheel = toyotaFactory.createWheel();
toyotaEngine.start(); // 输出: Toyota engine started
toyotaWheel.rotate(); // 输出: Toyota wheel rotating
const hondaFactory = new HondaFactory();
const hondaEngine = hondaFactory.createEngine();
const hondaWheel = hondaFactory.createWheel();
hondaEngine.start(); // 输出: Honda engine started
hondaWheel.rotate(); // 输出: Honda wheel rotating
代码运行结果
- 创建丰田工厂及部件:创建一个
ToyotaFactory实例,使用该工厂创建丰田发动机和车轮,并调用它们的方法,输出相应信息。- 创建本田工厂及部件:创建一个
HondaFactory实例,使用该工厂创建本田发动机和车轮,并调用它们的方法,输出相应信息。
4、建造者模式(Builder Pattern):
将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。
简单理解:就像建造房子,有不同的建造步骤,最终可以建成不同风格的房子。
// 建造者模式示例
// 产品类:汽车
function Car() {this.wheels = null;this.engine = null;this.color = null;
this.showInfo = function () {console.log(`Car with ${this.wheels} wheels, ${this.engine} engine and ${this.color} color`);};
}
//属性:
//wheels:用于存储汽车的车轮数量,初始值为 null。
//engine:用于存储汽车的发动机类型,初始值为 null。
//color:用于存储汽车的颜色,初始值为 null。
//方法:
//showInfo:该方法会将汽车的车轮数量、发动机类型和颜色信息拼接成字符串,并打印到控制台,方便查看汽车的具体配置。// 建造者类
function CarBuilder() {this.car = new Car();
this.setWheels = function (wheels) {this.car.wheels = wheels;return this;};
this.setEngine = function (engine) {this.car.engine = engine;return this;};
this.setColor = function (color) {this.car.color = color;return this;};
this.build = function () {return this.car;};
}
//属性:
//car:在构造函数中创建一个 Car 类的实例,后续的设置操作都是针对这个汽车对象进行的。
方法:
//setWheels:接收一个 wheels 参数,将其赋值给 this.car.wheels,并返回 this(即当前 CarBuilder 实例),这样可以实现链式调用。
//setEngine:接收一个 engine 参数,将其赋值给 this.car.engine,同样返回 this 以支持链式调用。
//setColor:接收一个 color 参数,将其赋值给 this.car.color,也返回 this 用于链式调用。
//build:返回已经构建好的 this.car 对象,标志着汽车构建完成。// 使用示例
const builder = new CarBuilder();
const car = builder.setWheels(4).setEngine('V8').setColor('Red').build();
car.showInfo(); // 输出: Car with 4 wheels, V8 engine and Red color
代码运行结果
- 创建一个
CarBuilder类的实例builder。- 通过链式调用
setWheels、setEngine和setColor方法,依次为汽车设置车轮数量、发动机类型和颜色。- 调用
build方法,得到最终构建好的Car对象,并将其赋值给car。- 调用
car.showInfo()方法,在控制台输出汽车的详细信息。

5、原型模式(Prototype Pattern):
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
简单理解:就像复印文件,有一个原始文件作为模板,然后可以复印出很多份一样的文件。
// 原型模式示例
const carPrototype = {brand: 'Unknown',model: 'Unknown',start: function () {console.log(`Starting the ${this.brand} ${this.model}`);},clone: function () {const clone = Object.create(this);return clone;}
};
//属性:
//brand:初始值为 'Unknown',用于表示汽车的品牌。
//model:初始值为 'Unknown',用于表示汽车的型号。
//方法:
//start:该方法会在控制台打印出启动当前汽车(根据 this.brand 和 this.model)的信息。这里的 this 指向调用该方法的对象。
//clone:使用 Object.create(this) 方法创建一个新对象,该新对象继承自当前原型对象(this)。这意味着新对象会拥有原型对象的所有属性和方法,并且对新对象属性的修改不会影响原型对象本身。最后返回这个克隆后的新对象。
// 使用示例
const car1 = carPrototype.clone();
car1.brand = 'Toyota';
car1.model = 'Corolla';
const car2 = carPrototype.clone();
car2.brand = 'Honda';
car2.model = 'Civic';
car1.start(); // 输出: Starting the Toyota Corolla
car2.start(); // 输出: Starting the Honda Civic
代码运行结果
- 创建
car1对象:
- 调用
carPrototype.clone()方法克隆原型对象,得到一个新的汽车对象car1。- 分别为
car1的brand和model属性赋值为'Toyota'和'Corolla'。- 创建
car2对象:
- 同样调用
carPrototype.clone()方法克隆原型对象,得到另一个新的汽车对象car2。- 为
car2的brand和model属性赋值为'Honda'和'Civic'。- 调用
start方法:
- 分别调用
car1.start()和car2.start()方法,由于this指向调用该方法的对象,所以会根据各自对象的brand和model属性输出相应的启动信息。

五、小结
设计模式在编程当中还是挺重要的,优点包括但不限于:代码复用性更高、可维护性更强、可扩展性更好。
有时间可以花点时间学习/复习一下,相信对我们的编程技术和编程思维会有很多进步~
相关文章:
【设计模式】01- 一文理解常用设计模式-“创建型模式”篇
一、前言 最近在复习设计模式,撰写、整理了内容和代码片段,和大家一起交流学习。 设计模式是软件设计中常见问题的典型解决方案。 修改记录 更新内容更新时间第一版 250212 更新了对文章中的模式代码示范的解释250214 二、模式分类 模式可以根据其意图…...
在ArcGIS JS API中使用WebGL实现波纹扩散特效
在现代WebGIS开发中,ArcGIS JS API 是一个非常强大的工具,它允许开发者创建丰富的地理信息应用。结合WebGL技术,我们可以实现更加复杂和炫酷的可视化效果。本文将介绍如何使用ArcGIS JS API结合WebGL实现一个波纹扩散特效。 波纹扩散效果 1 概…...
我用AI做数据分析之四种堆叠聚合模型的比较
我用AI做数据分析之四种堆叠聚合模型的比较 这里AI数据分析不仅仅是指AI生成代码的能力,我想是测试AI数据分析方面的四个能力,理解人类指令的能力、撰写代码的能力、执行代码的能力和解释结果的能力。如果这四个能力都达到了相当的水准,才可…...
《LSTM与HMM:序列建模领域的双雄对决》
在序列建模的广阔领域中,长短期记忆网络(LSTM)和隐马尔可夫模型(HMM)都是极为重要的工具,它们各自有着独特的优势和应用场景。下面将对两者在序列建模上的异同进行深入探讨。 相同点 序列数据处理能力&…...
Flutter 的 Widget Key 提议大调整?深入聊一聊 Key 的作用
Flutter 的 Widget Key 提议大调整?深入聊一聊 Key 的作用 在 Flutter 里,Key 对象存在的目的主要是区分和维持 Widget 的状态,它是控件在渲染树里的「复用」标识之一,这一点在之前的《深入 Flutter 和 Compose 在 UI 渲染刷新时…...
只需三步!5分钟本地部署deep seek——MAC环境
MAC本地部署deep seek 第一步:下载Ollama第二步:下载deepseek-r1模型第三步:安装谷歌浏览器插件 第一步:下载Ollama 打开此网址:https://ollama.com/,点击下载即可,如果网络比较慢可使用文末百度网盘链接 注:Ollama是…...
网络工程师 (31)VLAN
前言 VLAN(Virtual Local Area Network)即虚拟局域网,是一种将物理局域网划分成多个逻辑上独立的虚拟网络的技术。 一、定义与特点 定义:VLAN是对连接到的第二层交换机端口的网络用户的逻辑分段,不受网络用户的物理位置…...
浏览器网络请求全流程深度解析
一、核心流程概述 现代浏览器的网络请求过程是一个分层协作的精密系统,涉及应用层协议、传输层协议、操作系统内核及网络基础设施的协同工作。整个过程可抽象为以下关键阶段: 请求构建与初始化DNS解析与寻址TCP连接建立HTTP协议交互响应处理与资源解析…...
React历代主要更新
一、React 16之前更新 React Fiber是16版本之后的一种更新机制,使用链表取代了树,是一种fiber数据结构,其有三个指针,分别指向了父节点、子节点、兄弟节点,当中断的时候会记录下当前的节点,然后继续更新&a…...
【数据结构】(8) 二叉树
一、树形结构 1、什么是树形结构 根节点没有前驱,其它节点只有一个前驱(双亲/父结点)。所有节点可以有 0 ~ 多个后继,即分支(孩子结点)。每个结点作为子树的根节点,这些子树互不相交。 2、关于…...
navicat导出表结构到Excel 带字段备注
navicat导出表结构到Excel 带字段备注 SELECTCOLUMN_NAME AS 字段名称,COLUMN_TYPE AS 字段类型, IF( IS_NULLABLE NO, 否, 是 ) AS 是否必填,COLUMN_COMMENT AS 注释 FROMINFORMATION_SCHEMA.COLUMNS WHERE -- 数据库名table_schema vmscenter -- 表名AND table_name y…...
使用pocketpal-ai在手机上搭建本地AI聊天环境
1、下载安装pocketpal-ai 安装github的release APK 2、安装大模型 搜索并下载模型,没找到deepseek官方的,因为海外的开发者上传了一堆乱七八糟的deepseek qwen模型,导致根本找不到官方上传的……deepseek一开源他们觉得自己又行了。 点击之…...
程序诗篇里的灵动笔触:指针绘就数据的梦幻蓝图<10>
大家好啊,我是小象٩(๑ω๑)۶ 我的博客:Xiao Xiangζั͡ޓއއ 很高兴见到大家,希望能够和大家一起交流学习,共同进步。 今天我们继续来复习指针… 目录 一、看一段代码二、 一维数组传参的本质三、冒泡排序3.1 基本思想四、二…...
FPGA简介|结构、组成和应用
Field Programmable Gate Arrays(FPGA,现场可编程逻辑门阵列),是在PAL、GAL、CPLD等可编程器件的基础上进一步发展的产物, 是作为专用集成电路(ASIC)领域中的一种半定制电路而出现的,…...
[c语言日寄]在不完全递增序中查找特定要素
【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋:这是一个专注于C语言刷题的专栏,精选题目,搭配详细题解、拓展算法。从基础语法到复杂算法,题目涉及的知识点全面覆盖,助力你系统提升。无论你是初学者,还是…...
Golang的多团队协作编程模式与实践经验
Golang的多团队协作编程模式与实践经验 一、多团队协作编程模式概述 在软件开发领域,多团队协作编程是一种常见的工作模式。特别是对于大型项目来说,不同团队间需要协同合作,共同完成复杂的任务。Golang作为一种高效、并发性强的编程语言&…...
cv2.Sobel
1. Sobel 算子简介 Sobel 算子是一种 边缘检测算子,通过对图像做梯度计算,可以突出边缘。 Sobel X 方向卷积核: 用于计算 水平方向(x 方向) 的梯度。 2. 输入图像示例 假设我们有一个 55 的灰度图像,像素…...
Windows软件自动化利器:pywinauto python
Pywinauto WindowsAPP UI自动化 Windows软件自动化利器:pywinauto python...
关于 IoT DC3 中驱动(Driver)的理解
在开源IoT DC3物联网系统中,驱动(Driver)扮演着至关重要的角色,它充当了软件系统与物理设备之间的桥梁。驱动的主要功能是依据特定的通信协议连接到设备,并根据设备模板中配置的位号信息进行数据采集和指令控制。不同的…...
LogicFlow自定义节点:矩形、HTML(vue3)
效果: LogicFlow 内部是基于MVVM模式进行开发的,分别使用preact和mobx来处理 view 和 model,所以当我们自定义节点的时候,需要为这个节点定义view和model。 参考官方文档:节点 | LogicFlow 1、自定义矩形节点 custo…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...
