【设计模式】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…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...

2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...

2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...