从前端视角看设计模式之创建型模式篇

设计模式简介

"设计模式"源于GOF(四人帮)合著出版的《设计模式:可复用的面向对象软件元素》,该书第一次完整科普了软件开发中设计模式的概念,他们提出的设计模式主要是基于以下的面向对象设计原则:

  • 对接口编程而不是对实现编程
  • 优先使用对象组合而不是继承

根据该书所提到的,总共有 23 种设计模式,这些模式可以分为以下三大类:

1)创建型模式

这些模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象,这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活

包括:工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式

2)结构型模式

这些模式关注对象之间的组合和关系,旨在解决如何构建灵活且可复用的类和对象结构

包括:适配器模式、桥接模式、过滤器模式、组合模式、装饰器模式、外观模式、享元模式、代理模式

3)行为型模式

这些模式关注对象之间的通信和交互,旨在解决对象之间的责任分配和算法的封装

包括:责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、空对象模式、策略模式、模板模式、访问者模式

下图描述设计模式之间的关系:
在这里插入图片描述

设计模式的六大原则

1)开闭原则

开闭原则是指:对扩展开发,对修改关闭。在程序需要进行扩展的时候,不能去修改原有的代码,想要达到这样的效果,我们需要使用接口和抽象类

2)里氏代换原则

里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。该原则其实是对开闭原则的补充,实现开闭原则的关键步骤是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范

3)依赖倒转原则

这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体

4)接口隔离原则

接口隔离原则是指:使用多个隔离的接口,比使用单个接口要好,还有个意思是:降低类之间的耦合度

5)迪米特原则(又称:最少知道原则)

最少知道原则是指:一个实体尽量少地与其他实体发生相互作用,使得系统功能模块相互独立

6)合成复用原则

合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承

工厂模式

工厂模式提供了一种创建对象的方式,而无需指定要创建的具体类。通过使用工厂模式,可以将对象的创建逻辑封装到一个工厂类里,而不是在客户端代码中直接实例化对象

工厂模式主要有以下几种类型:

1)简单工厂模式

简单工厂模式不是一个正式的设计模式,但它是工厂模式的基础,它使用一个单独的工厂类来创建不同的对象,根据传入的参数决定创建哪种类型的对象

2)工厂方法模式

工厂方法模式定义了一个创建对象的接口,但由子类决定实例化哪个类,工厂方法将对象的创建延迟到子类

3)抽象工厂模式

抽象工厂模式提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类


当我们需要在不同条件下创建不同实例时可以使用工厂模式,它的使用场景主要有以下几个:

1)日志记录:日志可能记录到本地硬盘、远程服务器等,用户可以选择记录日志的位置

2)数据库访问:当用户不知道最终系统使用哪种数据库,或者数据库可能变化时

PS:工厂模式适用于生成复杂对象的场景,如果对象较为简单,通过 new 即可完成创建,而不必使用工厂模式,使用工厂模式会引入一个工厂类,增加系统复杂度


它的优缺点:

1)优点

  • 调用者只需要知道对象的名称即可创建对象
  • 扩展性高:如果需要增加新产品,只需扩展一个工厂类即可
  • 屏蔽了产品的具体实现,调用者只关心产品的接口

2)缺点

每次增加一个产品时,都需要增加一个具体类和对应的工厂,使系统中类的数量成倍增加,增加了系统的复杂度和具体类的依赖


工厂模式包含以下几个主要角色:

1)抽象产品

定义了产品的共同接口或抽象类,它可以是具体产品类的父类或接口,规定了产品对象的共同方法

2)具体产品

实现了抽象产品接口,定义了具体产品的特定行为和属性

3)抽象工厂

声明了创建产品的抽象方法,可以是接口或抽象类,它可以有多个方法用于创建不同类型的产品

4)具体工厂

实现了抽象工厂接口,负责实际创建具体产品的对象


我们通过以下一个简单的实例来展示工厂模式的实现,假设我们有不同种类的button需要创建,每个按钮有不同的实现

1)定义抽象产品和具体产品

Button类是一个抽象类(接口),它有两个方法:render()用于渲染按钮,onClick()用于按钮点击后的行为

WindowsButtonMacButton分别实现了Button接口,提供具体的渲染和点击行为

// 抽象产品:button
class Button {render() {throw new Error('方法 "render()" 被实现')}onClick() {throw new Error('方法 "onClick()" 被实现')}
}// 具体产品:Windows 按钮
class WindowsButton extends Button {render() {console.log('渲染 Windows 按钮')}onClick() {console.log('点击了 Windows 按钮')}
}// 具体产品:Mac 按钮
class MacButton extends Button {render() {console.log('渲染 Mac 按钮')}onClick() {console.log('点击了 Mac 按钮')}
}

2)定义抽象工厂和具体工厂

ButtonFactory是工厂接口,定义了createButton()方法,用来创建具体的按钮

WindowsButtonFactoryMacButtonFactory分别实现了createButton()方法,创建不同操作系统的按钮

// 工厂接口
class ButtonFactory {createButton() {throw new Error('方法 "createButton()" 被实现')}
}// 具体工厂:Windows 按钮工厂
class WindowsButtonFactory extends ButtonFactory {createButton() {console.log('创建 Windows 按钮')return new WindowsButton()}
}// 具体工厂:Mac 按钮工厂
class MacButtonFactory extends ButtonFactory {createButton() {console.log('创建 Mac 按钮')return new MacButton()}
}

3)使用工厂创建对象

renderButton() 是客户端方法,通过传入工厂对象来创建并使用按钮

// 客户端代码:根据需要选择不同的工厂来创建不同的按钮
function renderButton(factory) {const button = factory.createButton()button.render()                        button.onClick()                       
}// 模拟渲染不同操作系统的按钮
console.log('Windows 按钮:')
renderButton(new WindowsButtonFactory())console.log('Mac 按钮:')
renderButton(new MacButtonFactory())

执行上述代码,控制台打印出:

在这里插入图片描述

抽象工厂模式

抽象工厂模式是工厂模式的扩展,它提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定具体的类,换句话说,抽象工厂模式为一组产品提供了一个接口,这组产品可能有多个不同的具体实现,而每一个具体工厂类都负责创建这些产品的不同实现


它的使用场景主要有以下几个:

1)系统需要多个产品族的产品在一起工作,但不需要指定具体类时

2)系统需要独立于产品的创建、组合和表示时


它的优缺点:

1)优点

  • 确保同一产品族的对象一起工作
  • 客户端不需要知道每个对象的具体类,简化了代码

2)缺点

增加一个新的产品族需要修改抽象工厂和所有具体工厂的代码


假设我们需要在多个操作系统上创建不同风格的按钮和文本框,将使用抽象工厂模式来创建这些 UI 元素,以便在不同操作系统上使用相应的样式

1)定义抽象产品接口

定义ButtonTextBox作为抽象产品,它们是各个操作系统上的 UI 元素

// 抽象产品:Button
class Button {render() {throw new Error('方法 "render()" 被实现')}onClick() {throw new Error('方法 "onClick()" 被实现')}
} 
// 抽象产品:TextBox
class TextBox {render() {throw new Error('方法 "render()" 被实现')}onFocus() {throw new Error('方法 "onFocus()" 被实现')}
}

2)定义具体产品

定义具体产品类:WindowsButtonMacButtonWindowsTextBoxMacTextBox,它们实现了上述的抽象产品接口

// 具体产品:Windows 按钮
class WindowsButton extends Button {render() {console.log('渲染 Windows 按钮')}onClick() {console.log('点击了 Windows 按钮')}
} 
// 具体产品:Mac 按钮
class MacButton extends Button {render() {console.log('渲染 Mac 按钮')}onClick() {console.log('点击了 Mac 按钮')}
}
// 具体产品:Windows 文本框
class WindowsTextBox extends TextBox {render() {console.log('渲染 Windows 文本框')}onFocus() {console.log('Windows 文本框获得焦点')}
}
// 具体产品:Mac 文本框
class MacTextBox extends TextBox {render() {console.log('渲染 Mac 文本框')}onFocus() {console.log('Mac 文本框获得焦点')}
}

3)定义抽象工厂接口

UIFactory是抽象工厂接口,定义了两个方法:createButtoncreateTextBox,用来创建按钮和文本框

// 抽象工厂接口:UIFactory
class UIFactory {createButton() {throw new Error('方法 "createButton()" 必须被实现')}createTextBox() {throw new Error('方法 "createTextBox()" 必须被实现')}
}

4)定义具体工厂

具体工厂WindowsFactoryMacFactory负责实例化具体的 UI 元素(按钮和文本框)

// 具体工厂:Windows 工厂
class WindowsFactory extends UIFactory {createButton() {console.log('创建 Windows 按钮')return new WindowsButton()}createTextBox() {console.log('创建 Windows 文本框')return new WindowsTextBox()}
}
// 具体工厂:Mac 工厂
class MacFactory extends UIFactory {createButton() {console.log('创建 Mac 按钮')return new MacButton()}createTextBox() {console.log('创建 Mac 文本框')return new MacTextBox()}
}

5)客户端使用工厂

根据需求选择不同的工厂来创建产品(按钮和文本框),而不关心具体的产品实现

// 客户端代码:根据工厂创建 UI 元素
function renderUI(factory) {const button = factory.createButton()  button.render()                        button.onClick()                       const textBox = factory.createTextBox()  textBox.render()                        textBox.onFocus()                       
}console.log('渲染 Windows 风格的 UI:')
renderUI(new WindowsFactory())console.log('渲染 Mac 风格的 UI:')
renderUI(new MacFactory())

执行上述代码,控制台打印出:

在这里插入图片描述

单例模式

单例模式确保一个类只有一个实例,并提供了一个全局访问点来访问该实例,需要注意的是:

1)单例类只能有一个实例

2)单例类必须自己创建自己的唯一实例

3)单例类必须给其他对象提供这一实例


当需要控制实例数量,节省系统资源时可以使用单例模式,它的使用场景主要有以下几个:

1)生成唯一序列号

2)创建消耗资源过多的对象,比如:I/O、数据库连接等

3)如果某个计算的结果是全局唯一且不希望重复计算,可以使用单例模式缓存该结果,确保第一次计算后复用该结果


它的缺点:

1)没有接口,不能继承

2)与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心实例化方式


单例模式可以使用以下不同的方法来实现:

1)懒汉式

首次调用时创建实例,适合资源消耗较大的情况

2)饿汉式

类加载时创建实例,适合在程序启动时就需要用到实例的情况

懒汉式

懒汉式的单例模式是在需要实例的时候才创建实例,实例是延迟加载的,只有在第一次访问时才会创建

第一次创建instance1时,Singleton的构造函数会初始化实例并存储在Singleton.instance中;第二次创建instance2时,由于Singleton.instance已经存在,构造函数直接返回已有的实例

class Singleton {constructor() {// 如果实例已经存在,直接返回该实例if (Singleton.instance) {return Singleton.instance}// 否则就初始化实例this.value = Math.random()Singleton.instance = this}getValue() {return this.value}
}// 测试
const instance1 = new Singleton()
console.log(instance1.getValue())const instance2 = new Singleton()
console.log(instance2.getValue())console.log(instance1 === instance2)  // 输出 true,说明是同一个实例

在 JavaScript 中,单线程模型通常不会遇到并发问题,但是在多线程环境中,如果多个线程同时调用new Singleton(),可能会创建多个实例,违背了单例模式的原则

为了避免多个线程并发访问时创建多个实例,我们可以通过加锁来确保同一时刻只有一个线程能创建实例,使用 synchronized 来进行加锁

在 JavaScript 中实现"上锁"的概念时,通常使用一个标志变量(如lock)来模拟锁的功能

通过Singleton.lock来确保只有一个线程能执行实例创建的代码,其他线程在此期间会被阻塞,直到锁被释放;在try...finally结构中,确保即使发生异常,也能释放锁

class Singleton {constructor() {// 如果实例已经存在,直接返回该实例if (Singleton.instance) {return Singleton.instance}// 模拟线程安全的加锁机制if (!Singleton.lock) {Singleton.lock = true  // 上锁try {// 如果没有实例,则创建一个this.value = Math.random()Singleton.instance = this} finally {Singleton.lock = false  // 解锁}}}getValue() {return this.value}
}// 测试
const instance1 = new Singleton()
console.log(instance1.getValue())const instance2 = new Singleton()
console.log(instance2.getValue())console.log(instance1 === instance2)  // 输出 true,说明是同一个实例

饿汉式

饿汉式的单例模式与懒汉式不同,它在类加载时就创建好实例,饿汉式实现不需要考虑线程安全问题,因为实例在类加载时就创建好了,只有一个线程能访问类加载阶段

在下面的实现中,Singleton.instance是类加载时就创建好的静态属性,因此无论多少次访问,都返回相同的实例

class Singleton {static instance = new Singleton()constructor() {if (Singleton.instance) {return Singleton.instance}this.value = Math.random() }getValue() {return this.value}
}// 测试
const instance1 = Singleton.instance
console.log(instance1.getValue())const instance2 = Singleton.instance
console.log(instance2.getValue())console.log(instance1 === instance2)  // 输出 true,说明是同一个实例

建造者模式

建造者模式将复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的对象


它的使用场景主要有以下:

1)当一个对象的构建过程很复杂,可能涉及多个步骤,且这些步骤可以独立进行

2)需要支持产品的多种表现形式(不同配置、不同组合)

PS:与工厂模式的区别是:建造者模式更加关注于零件装配的顺序


它的优缺点:

1)优点

  • 分离构建过程和表示,可以构建不同的表示
  • 代码复用性高,可以在不同的构建过程中重复使用相同的建造者

2)缺点

  • 如果产品属性较少,该模式会导致代码冗余
  • 增加了系统的类和对象数量

建造者模式包含以下几个主要角色:

1)产品

要构建的复杂对象,产品类通常包含多个部分或属性

2)抽象建造者

定义了构建产品的抽象接口,包括构建产品的各个部分的方法

3)具体建造者

实现抽象建造者接口,具体确定如何构建产品的各个部分,并负责返回最终构建的产品

4)指导者

负责调用建造者的方法来构建产品,指导者并不了解具体的构建过程,只关心产品的构建顺序和方式


假设我们需要构建一辆汽车,汽车有多个部件,不同配置的汽车有不同的部件组合,下面通过建造者模式来组织这个构建过程

1)定义产品类

构建一个汽车产品类,它有多个部件:引擎、轮胎、车窗

class Car {constructor() {this.engine = nullthis.tires = nullthis.windows = null}show() {console.log(`汽车配置:引擎: ${this.engine}, 轮胎: ${this.tires}, 车窗: ${this.windows}`)}
}

2)定义抽象建造者

建造者类定义了构建汽车的各个步骤,但不包含具体的实现

//抽象建造者:CarBuilder
class CarBuilder {buildEngine() {throw new Error('子类实现 buildEngine 方法')}buildTires() {throw new Error('子类实现 buildTires 方法')}buildWindows() {throw new Error('子类实现 buildWindows 方法')}getCar() {throw new Error('子类实现 getCar 方法')}
}

3)定义具体建造者

具体建造者类继承CarBuilder,并实现了具体的构建过程,这里定义了两种不同配置的汽车:普通汽车和豪华汽车

//具体建造者:普通汽车 NormalCarBuilder
class NormalCarBuilder extends CarBuilder {constructor() {super()this.car = new Car()}buildEngine() {this.car.engine = '普通引擎'}buildTires() {this.car.tires = '普通轮胎'}buildWindows() {this.car.windows = '普通车窗'}getCar() {return this.car}
}
//具体建造者:豪华汽车 LuxuryCarBuilder
class LuxuryCarBuilder extends CarBuilder {constructor() {super()this.car = new Car()}buildEngine() {this.car.engine = '豪华引擎'}buildTires() {this.car.tires = '豪华轮胎'}buildWindows() {this.car.windows = '豪华车窗'}getCar() {return this.car}
}

4)定义指导者

指导者负责按照一定的顺序,调用建造者类的方法,来创建汽车

//指导者:Director
class Director {constructor(builder) {this.builder = builder}construct() {this.builder.buildEngine()this.builder.buildTires()this.builder.buildWindows()}
}

5)客户端

客户端通过指导者来控制建造过程,最终得到一个构建好的汽车对象

// 客户端代码
const normalCarBuilder = new NormalCarBuilder()
const normalDirector = new Director(normalCarBuilder)normalDirector.construct()
const normalCar = normalCarBuilder.getCar()
normalCar.show() // 输出: 汽车配置:引擎: 普通引擎, 轮胎: 普通轮胎, 车窗: 普通车窗const luxuryCarBuilder = new LuxuryCarBuilder()
const luxuryDirector = new Director(luxuryCarBuilder)luxuryDirector.construct()
const luxuryCar = luxuryCarBuilder.getCar()
luxuryCar.show() // 输出: 汽车配置:引擎: 豪华引擎, 轮胎: 豪华轮胎, 车窗: 豪华车窗

原型模式

原型模式通过复制现有的对象来创建新对象,而不是通过直接构造新的对象,避免了重复初始化复杂对象的开销


它的使用场景主要有以下几个:

1)类初始化需要消耗大量资源,如数据、硬件资源

2)通过 new 创建对象需要复杂的数据准备或访问权限时

3)一个对象需要多个修改者

PS:与直接实例化类创建新对象不同,原型模式通过拷贝现有对象生成新对象


它的优缺点:

1)优点

  • 性能提高
  • 避免构造函数的约束

2)缺点

配置克隆方法需要全面考虑类的功能,对已有类可能较难实现,特别是处理不支持串行化的间接对象或含有循环结构的引用时


原型模式包含以下几个主要角色:

1)原型接口

定义一个用于克隆自身的接口,通常包含一个 clone() 方法

2)具体原型类

实现圆形接口的具体类,负责实际的克隆操作,通常使用浅拷贝或深拷贝来复制自身

  • 浅拷贝:复制对象时,原始对象的属性值会被复制到新对象中,但如果属性是引用类型,则会复制引用而不是实际的对象
  • 深拷贝:不仅复制对象本身的属性,还会递归地复制对象中引用类型的属性,从而确保新对象完全独立于原始对象

3)客户端

使用原型实例来创建新的对象,客户端调用原型对象的 clone() 方法来创建新的对象,而不是直接使用构造函数


假设我们需要复制一个游戏角色,这个角色有多个属性,如名字、血量、装备等,通过克隆原始角色来创建一个新的角色

1)创建一个GameCharacter

// 原型类:游戏角色
class GameCharacter {constructor(name, health, weapons) {this.name = name      this.health = health this.weapons = weapons  }// 显示角色信息display() {console.log(`角色:${this.name}, 血量:${this.health}, 武器:${this.weapons.join(', ')}`)}// 克隆方法 - 浅拷贝clone() {return new GameCharacter(this.name, this.health, [...this.weapons])}
}

2)创建一个简单的角色对象

// 创建一个角色
const originalCharacter = new GameCharacter("战士", 100, ["剑", "盾"])
originalCharacter.display()

3)克隆角色

// 克隆角色
const clonedCharacter = originalCharacter.clone()
clonedCharacter.display()

4)修改克隆后的对象

修改克隆后的角色,看看它是否独立于原始对象:

// 修改克隆后的角色
clonedCharacter.name = "弓箭手"
clonedCharacter.health = 80
clonedCharacter.weapons.push("弓")// 显示修改后的角色信息
clonedCharacter.display()// 显示原始角色信息
originalCharacter.display()

从以下输出中可以看出,原始角色和克隆后的角色是独立的,修改克隆角色的属性不会影响原始角色

在这里插入图片描述

当前的 clone 方法是浅拷贝,它会直接复制对象的引用类型属性,如 weapons 数组,如果修改了克隆角色的weapons,会影响到原始角色

为了避免这个问题,我们可以在 clone 方法中使用深拷贝,保证即使 weapons 是引用类型,也会完全复制

// 深拷贝:确保复制所有引用类型的内容
clone() {return new GameCharacter(this.name, this.health, JSON.parse(JSON.stringify(this.weapons)))
}

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

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

相关文章

Pandas数据合并:concat与merge

目录 一、concat方法 1. 基本语法 2. 示例 示例1:按行合并(垂直方向) 示例2:按列合并(水平方向) 示例3:使用joininner进行内连接 示例4:处理列名冲突 二、merge方法 1. 基本…

docker的数据卷与dockerfile自定义镜像

docker的数据卷与dockerfile自定义镜像 一. docker的数据卷数据卷容器 二. dockerfile自定义镜像2.1 dockerfile的命令格式镜像的操作命令add和copy的区别 容器启动的命令 2.2 run命令2.3 其它端口映射 三. 练习 一. docker的数据卷 容器于宿主机之间,或者容器和容…

【大数据】机器学习 -----关于data.csv数据集分析案例

打开表 import pandas as pd df2 pd.read_csv("data.csv",encoding"gbk") df2.head()查看数据属性(列标题,表形状,类型,行标题,值) print("列标题:",df2.columns)Data…

开发规范

开发规范 企业项目开发有2种开发模式:前后台混合开发和前后台分离开发。 前后台混合开发 顾名思义就是前台后台代码混在一起开发,如下图所示: 这种开发模式有如下缺点: 沟通成本高:后台人员发现前端有问题&#xf…

【Mysql进阶知识】从.SQL文件中执行SQL语句

目录 方法一:使用source命令导入 方法二:使用mysql客户端导入 方法一:使用source命令导入 有时候我们需要从 SQL 文件执行一些 SQL 语句,比如要把一个数据库从一台服务器 A 复制到另一台服务器 B 上,那么可以先从服务…

springMVC---resultful风格

目录 一、创建项目 pom.xml 二、配置文件 1.web.xml 2.spring-mvc.xml 三、图解 四、controller 一、创建项目 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi…

RustDesk ID更新脚本

RustDesk ID更新脚本 此PowerShell脚本自动更新RustDesk ID和密码&#xff0c;并将信息安全地存储在Bitwarden中。 特点 使用以下选项更新RustDesk ID&#xff1a; 使用系统主机名生成一个随机的9位数输入自定义值 为RustDesk生成新的随机密码将RustDesk ID和密码安全地存储…

告别 Excel,拥抱 R 语言:开启数据分析新时代

在这个数据驱动的时代&#xff0c;数据分析已然成为每个行业的核心竞争力。从市场营销到金融领域&#xff0c;从医疗健康到教育行业&#xff0c;数据无处不在&#xff0c;深刻影响着每一个决策。然而&#xff0c;面对日益复杂的数据集&#xff0c;单纯依靠 Excel 进行分析&…

LabVIEW驱动电机实现样品自动搜索

利用LabVIEW控制电机驱动相机在XY平面上进行扫描&#xff0c;以检测样品位置。样品最初可能位于相机视野范围之外&#xff0c;需要实现自动搜索样品位置并完成精确定位扫描的功能。该系统需具有以下特点&#xff1a; 高效搜索&#xff1a;能够快速确定样品位置&#xff0c;缩短…

【C语言】_字符串拷贝函数strcpy

目录 1. 函数声明及功能 2. 使用示例 3. 注意事项 4. 模拟实现 4.1 第一版&#xff1a;基本功能判空const修饰 4.2 第二版&#xff1a;优化对于\0的单独拷贝 4.3 第三版&#xff1a;仿strcpy的char*返回值 1. 函数声明及功能 char * strcpy ( char * destination, cons…

大模型WebUI:Gradio全解11——Chatbots:融合大模型的多模态聊天机器人(3)

大模型WebUI&#xff1a;Gradio全解11——Chatbot&#xff1a;融合大模型的多模态聊天机器人&#xff08;3&#xff09; 前言本篇摘要11. Chatbot&#xff1a;融合大模型的多模态聊天机器人11.3 组件Chatbot及ChatMessage11.3.1 Chatbot&#xff1a;聊天机器人组件1. API参数2.…

细说STM32F407单片机窗口看门狗WWDG的原理及使用方法

目录 一、窗口看门狗的工作原理 1、递减计数器 2、窗口值和比较器 3、看门狗的启动 4、提前唤醒中断 二、窗口看门狗的HAL驱动程序 1、窗口看门狗初始化 2.窗口看门狗刷新 3.EWI中断及其处理 三、不开启EWI的WWDG示例 1、示例功能 2、项目设置 &#xff08;1&…

Docker部署Spring Boot + Vue项目

目录 前提条件 概述 下载代码 打开代码 Docker创建网络 MySQL容器准备 MySQL数据库配置 启动MySQL容器 测试连接MySQL 初始化MySQL数据 Redis容器准备 修改Redis配置 启动redis容器 部署后端 后端代码打包 上传jar包到Linux 创建Dockerfile 构建镜像 运行后…

基于Oracle与PyQt6的电子病历多模态大模型图形化查询系统编程构建

一、引言 1.1 研究背景阐述 在当今数字化时代,医疗行业正经历着深刻的变革,数字化转型的需求日益迫切。电子病历(EMR)作为医疗信息化的核心,其管理的高效性和数据利用的深度对于提升医疗服务质量、优化临床决策以及推动医学研究具有至关重要的意义。传统的电子病历管理系…

万字长文介绍ARINC 653,以及在综合模块化航空电子设备(IMA)中的作用

文章目录 一、引言二、ARINC 653背景三、整体系统架构四、应用/执行&#xff08;APEX&#xff09;接口五、ARINC 653 RTOS内部机制六、健康监测功能七、软件应用八、ARINC 653现状九、总结 一、引言 在现代航空领域&#xff0c;综合模块化航空电子设备&#xff08;IMA&#xf…

在eNSp上telnet一下吧

在上篇博客&#xff1a;DNS 我们提到了telnet和设备带外管理、带内管理&#xff0c;它确实是非常有趣的一个知识点哦&#xff0c;接下来我们一起来学习学习吧~ Telnet&#xff08;远程登陆协议&#xff09; Telnet基于TCP 23号端口&#xff0c;典型的C/S架构模式&#xff0c;是…

音频语言模型与多模态体系结构

音频语言模型与多模态体系结构 多模态模型正在创造语言、视觉和语音等以前独立的研究领域的协同效应。这些模型使用通用架构,将每种模式视为不同的“token”,使它们能够以一种与人类认知非常相似的方式联合建模和理解世界。 ​ ​可以将多模态分为两个主要领域:输入空间(…

【深度学习】关键技术-正则化(Regularization)

正则化&#xff08;Regularization&#xff09; 是一种用于防止模型过拟合的技术。它通过在损失函数中添加额外的约束项&#xff0c;限制模型的复杂度&#xff0c;从而提高模型的泛化能力。 正则化的主要作用 防止过拟合&#xff1a;通过抑制模型对训练数据的过度拟合&#xf…

怎么在iPhone手机上使用便签进行记录?

宝子们&#xff0c;在这个快节奏的时代&#xff0c;灵感的火花总是一闪而过&#xff0c;待办事项也常常让人应接不暇。好在咱们的 iPhone手机便签超给力&#xff0c;能满足各种记录需求&#xff01;今天就来给大家分享一下&#xff0c;如何在 iPhone 手机上巧用便签&#xff0c…

渗透测试之越权漏洞详解 水平越权 垂直越权 目录越权 SQL跨库查询越权 以及未授权漏洞 一篇文章说明白

目录 什么是越权 越权漏洞形成的原因是&#xff1a; 越权常见分类 漏洞产生条件 越权细分类 水平越权&#xff1a; 水平越权解释&#xff1a; 垂直越权&#xff1a; 垂直越权示例: 解释: 修复建议 例如 越权漏洞易发生的点 1.基础参数 2.多阶段验证 3.基于参数的访…