【设计模式】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…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
