Javascript 设计模式
设计模式的五大设计原则(SOLID)
单一职责:一个程序只需要做好一件事。如果功能过于复杂就拆分开,保证每个部分的独立
开放封闭原则:对扩展开放,对修改封闭。增加需求时,扩展新代码,而不是修改源代码。这是软件设计的终极目标。
里氏置换原则:子类能覆盖父类,父类能出现的地方子类也能出现。
接口独立原则:保持接口的单一独立,避免出现“胖接口”。这点目前在TS中运用到。
依赖导致原则:面向接口编程,依赖于抽象而不依赖于具体。使用方只专注接口而不用关注具体类的实现。俗称“鸭子类型”
工厂模式
工厂模式是用来创建对象的常见设计模式,在不暴露创建对象的具体逻辑,而是将逻辑进行封装,那么它就可以被称为工厂。工厂模式又叫做静态工厂模式,由一个工厂对象决定创建某一个类的实例。
class Plant {constructor(name) {this.name = name;}grow() {console.log("grow up");}
}class Apple extends Plant {constructor(name, flavour) {super(name)this.flavour = flavour;}
}class Orange extends Plant {constructor(name, flavour) {super(name)this.flavour = flavour;}
}class Factory {static create(type) {switch (type) {case 'apple':return new Apple('xiao ping','sweet')case 'orange':return new Orange('xiao ju','sour')default:throw new Error("Unknown plant type")}}
}let apple = Factory.create('apple');
console.log(apple.flavour)
let orange = Factory.create('orange');
console.log(orange.flavour)
小结:
优点
调用者创建对象时只要知道其名称即可
扩展性高,如果要新增一个产品,直接扩展一个工厂类即可。
隐藏产品的具体实现,只关心产品的接口。
缺点
每次增加一个产品时,都需要增加一个具体类,这无形增加了系统内存的压力和系统的复杂度,也增加了具体类的依赖
单例模式
单例模式的思路是:保证一个类只能被实例一次,每次获取的时候,如果该类已经创建过实例则直接返回该实例,否则创建一个实例保存并返回。
单例模式很常用,比如:
vue项目中的Vue实例
node项目中的App实例
vuex react-redux 中的store
全局唯一的组件,像弹出框,模态窗口,购物车,登录框等
class LoginFrame {static instance = nullconstructor(state){this.state = state}show(){if(this.state === 'show'){console.log('登录框已显示')return}this.state = 'show'console.log('登录框展示成功')}hide(){if(this.state === 'hide'){console.log('登录框已隐藏')return}this.state = 'hide'console.log('登录框隐藏成功')}// 通过静态方法获取静态属性instance上是否存在实例,如果没有创建一个并返回,反之直接返回已有的实例static getInstance(state){if(!this.instance){this.instance = new LoginFrame(state)}return this.instance}
}
const p1 = LoginFrame.getInstance('show')
const p2 = LoginFrame.getInstance('hide')
console.log(p1 === p2) // true
小结:
优点
内存中只有一个实例,减少了内存的开销。
避免了对资源多重的占用。
缺点
违反了单一职责,一个类应该只关心内部逻辑,而不用去关心外部的实现
原型模式
function Person(name){this.name = name;
}Person.prototype.getName = function(){return this.name;
}let p1 = new Person('san')
let p2 = new Person('si')
console.log(p1.getName === p2.getName)
更多关于prototype的知识请去 JS原型与原型链详解
适配器模式
适配器模式的作用是解决两个软件实体间的接口不兼容的问题。使用适配器模式之后,原本由于接口由于接口不兼容而不能工作的两个软件实体可以一起工作。
class Power {charge(){return '220v'}
}class Adapter{constructor(){this.power = new Power()}charge(){let v= this.power.charge();return `${v} => 12v`}
}class Client{constructor(){this.adapter = new Adapter()}use(){console.log(this.adapter.charge())}
}let client = new Client()
client.use()
小结:
优点
让任何两个没有关联的类可以同时有效运行,并且提高了复用性、透明度、以及灵活性
缺点
过多的使用适配器模式,会让系统变得零乱,不易整体把控。建议在无法重构的情况下使用适配器。
代理模式
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”
let lily = {name: 'lily',age: '30',height: '160'
}// new Proxy(target, handler);
// new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。let lilyMa = new Proxy(lily, {//get方法的两个参数分别是目标对象和所要访问的属性。get(target, key) {if (key === 'age') {return target.age - 2} else if (key === 'height') {return target.height + 5} else {return target[key]}},set(target,key,value) {if(key ==='boyfriend'){let boyfriend = value;if(boyfriend.age >40){throw new Error('too old!')} else if(boyfriend.salary <20000){throw new Error('too poor!')} else{target[key] = value}}}
}) console.log(lilyMa.age)
lilyMa.boyfriend = {age:35,salary:25000,height:180}
小结:
代理模式符合开放封闭原则
本体对象和代理对象拥有相同的方法,在用户看来并不知道请求的本体对象还是代理对象。
代理模式 vs 适配器模式 适配器提供不同的接口,代理模式提供一摸一样的接口
代理模式 vs 装饰器模式 装饰器模式原来的功能不变还可以使用,代理模式改变原来的功能
优点
职责清晰,高扩展性,智能化
缺点
当对象和对象之间增加了代理可能会影响到处理的速度。
实现代理需要额外的工作,有些代理会非常的复杂。
观察者模式(订阅-发布模式)
观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,
所有依赖于它的对象将得到通知。
如:当你给DOM绑定一个事件就已经使用了发布订阅模式,通过订阅DOM上的click事件,当被点击时会向订阅者发布消息。
class Star{constructor(name){this.name = name;this.state = '';this.observers = [];}getState(){return this.state;}setState(state){this.state = state;this.notifyAllObservers()}attach(observer){this.observers.push(observer)}notifyAllObservers(){if(this.observers.length>0){this.observers.forEach(observer=>observer.update())}}
}class Fun{constructor(name,star){this.name = name;this.star = star;this.star.attach(this)}update(){console.log(`${this.star.name} know ${this.star.getState()}`)}
}let s = new Star('liushishi')
let f = new Fun('me',s)
s.setState('xinai')
小结:
发布订阅模式可以使代码解耦,满足开放封闭原则
当过多的使用发布订阅模式,如果订阅消息始终都没有触发,则订阅者一直保存在内存中。
优点
观察者和被观察者它们之间是抽象耦合的。并且建立了触发机制。
缺点
当订阅者比较多的时候,同时通知所有的订阅者可能会造成性能问题。
在订阅者和订阅目标之间如果循环引用执行,会导致崩溃。
发布订阅模式没有办法提供给订阅者所订阅的目标它是怎么变化的,仅仅只知道它变化了。
装饰器模式
装饰者模式能够在不更改源代码自身的情况下,对其进行职责添加。相比于继承装饰器的做法更轻巧。通俗的讲我们给心爱的手机上贴膜,带手机壳,贴纸,这些就是对手机的装饰。
class Duck {constructor(name) {this.name = name;}eat(food) {console.log(`eat ${food}`)}
}class TangDuck {constructor(name) {this.duck = new Duck(name);}eat(food) {this.duck.eat(food);console.log('thanks')}
}let d = new TangDuck();
d.eat('apple');
还有ES6的Decorator
优点
装饰类和被装饰类它们之间可以相互独立发展,不会相互耦合,装饰器模式是继承的一个替代模式,它可以动态的扩展一个实现类的功能。
缺点
多层的装饰会增加复杂度
外观模式
外观模式本质就是封装交互,隐藏系统的复杂性,提供一个可以访问的接口。由一个将子系统一组的接口集成在一起的高层接口,以提供一个一致的外观,减少外界与多个子系统之间的直接交互,从而更方便的使用子系统。
class Sum{sum(a,b){return a+b}
}class Minus{minus(a,b){return a-b}
}
class Mutify{mutify(a,b){return a*b}
}
class Divide{divide(a,b){return a/b}
}class Calculate{constructor(a,b){this.sumc = new Sum(a,b);this.minusc = new Minus(a,b);this.mutifyc = new Mutify(a,b);this.dividec = new Divide(a,b);}sum(a,b){return this.sumc.sum(a,b)}minus(a,b){return this.minusc.minus(a,b)}mutify(a,b){return this.mutifyc.mutify(a,b)}divide(a,b){return this.dividec.divide(a,b)}
}let calculate = new Calculate()
console.log(calculate.sum(1,2))
优点
减少系统的相互依赖,以及安全性和灵活性
缺点
违反开放封闭原则,有变动的时候更改会非常麻烦,即使继承重构都不可行。
状态模式
允许一个对象在其内部状态改变的时候改变其行为,对象看起来似乎修改了它的类,通俗一点的将就是记录一组状态,每个状态对应一个实现,实现的时候根据状态去运行实现。
class SuccessState {show(){console.log('green')}
}class WarningState {show(){console.log('yellow')}
}class ErrorState {show(){console.log('red')}
}class Battery {constructor(){this.amout = 'high'this.state = new SuccessState()}show(){this.state.show();if(this.amout == 'high'){this.amout= 'middle';this.state = new WarningState()} else if(this.amout == 'middle'){this.amout= 'low';this.state = new ErrorState()}}
}let b = new Battery()
b.show()
b.show()
b.show()
优点
将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点
状态模式的使用必然会增加系统类和对象的个数。
状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
状态模式对"开闭原则"的支持并不太好,对切换状态的状态模式增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
策略模式
策略模式指的是定义一系列算法,把他们一个个封装起来,目的就是将算法的使用和算法的实现分离开来。同时它还可以用来封装一系列的规则,比如常见的表单验证规则,只要这些规则指向的目标一致,并且可以被替换使用,那么就可以用策略模式来封装它们。
class Customer{constructor(kind){this.kind = kind;}pay(amount){return this.kind.pay(amount)}
}class Normal{pay(amount){return amount}
}class Member{pay(amount){return amount*.9}
}class VIP{pay(amount){return amount*.8}
}let c1 = new Customer(new Normal()).pay(100);
console.log(c1)
let c2 = new Customer(new Member()).pay(100)
console.log(c2)
let c3 = new Customer(new VIP()).pay(100)
console.log(c3)
优点
算法可以自由切换,避免了使用多层条件判断,增加了扩展性
缺点
策略类增多,所有策略类都需要对外暴露。
相关文章:
Javascript 设计模式
设计模式的五大设计原则(SOLID)单一职责:一个程序只需要做好一件事。如果功能过于复杂就拆分开,保证每个部分的独立开放封闭原则:对扩展开放,对修改封闭。增加需求时,扩展新代码,而不是修改源代码。这是软件设计的终极…...
JAVA-文档工具screw-gui
前言 为什么萌生了写文档工具得想法,因为在项目开发得过程中,经常需要补充一些文档,比如数据库文档、详细设计文档等等,文档与项目相绑定,在项目需求新增或变更时,文档也需要反反复复得修改。 1. 数据库…...
开源鸿蒙南向嵌入学习笔记——NAPI框架学习(一)
开源鸿蒙南向嵌入学习笔记——NAPI框架学习(一) 前言——系列介绍 本系列文章主要是记录笔者在鸿蒙南向的学习与工作中的知识点笔记记录,其中不止会针对鸿蒙中的学习问题进行思考与记录,也会对涉及到的一些嵌入式等其他领域知识&…...
Spring - Spring框架概述面试题总结
文章目录01. 什么是Spring?02. Spring框架的设计目标,设计理念,和核心是什么?03. Spring的优点是什么?04. Spring框架中都用到了哪些设计模式?05. Spring有哪些应用场景?06. Spring由哪些模块组成…...
学习python好就业么
Python的普及与数据挖掘、人工智能和数值计算等领域的蓬勃发展相关,但同时也与普遍编程需求的增加有关。 Python作为人工智能的头号语言,一方面会吸引大量计划从事人工智能的人来学习,另一方面自然也带动了网络上对这门“新语言”的关注和讨…...
瑞幸咖啡的最终目标并不是做国内市场大哥
出品 | 何玺 排版 | 叶媛 日前,瑞幸咖啡发布2022年第四季度及全年财报。数据显示,在刚刚过去的2022年,瑞幸咖啡首次实现了营收超百亿,门店规模也超越老对手星巴克,成为了国内第一连锁咖啡品牌。 那么,瑞幸…...
GPT 模型介绍 | GPT3 / GPT3.5 + Flask | Github源码链接
1. 模型介绍 Chatgpt 使用与 InstructGPT相同的方法,使用来自人类反馈的强化学习 (RLHF) 来训练该模型,但数据收集设置略有不同。我们使用监督微调训练了一个初始模型:人类 AI 训练员提供对话,他们在对话中扮演双方——用户和 AI…...
蓝桥杯入门即劝退(二十六)组合问题(回溯算法)
-----持续更新Spring入门系列文章----- 如果你也喜欢Java和算法,欢迎订阅专栏共同学习交流! 你的点赞、关注、评论、是我创作的动力! -------希望我的文章对你有所帮助-------- 专栏:蓝桥杯系列 一、题目描述 给定两个整数 n …...
现代卷积神经网络(ResNet)
专栏:神经网络复现目录 本章介绍的是现代神经网络的结构和复现,包括深度卷积神经网络(AlexNet),VGG,NiN,GoogleNet,残差网络(ResNet),稠密连接网络…...
PTA:L1-019 谁先倒、L1-020 帅到没朋友、L1-021 重要的话说三遍(C++)
目录 L1-019 谁先倒 问题描述: L1-020 帅到没朋友 问题描述: 实现代码(只过了部分): L1-021 重要的话说三遍 问题描述: 实现代码: 无解析 L1-019 谁先倒 问题描述: 划拳是…...
STL常见容器之set/multiset、map/multimap
set/multiset—集合容器 特点 所有元素都会在插入时自动被排序 本质 set/multiset属于关联式容器,底层结构是二叉树实现 set和multiset区别 set不可以插入重复数据,而multiset可以set插入数据的同时会返回插入结果,表示插入是否成功multiset…...
ThreadLocal 实现原理
每个 Thread 中都存储着一个成员变量:ThreadLocalMap /** InheritableThreadLocal values pertaining to this thread. This map is* maintained by the InheritableThreadLocal class.*/ThreadLocal.ThreadLocalMap inheritableThreadLocals null; ThreadLocal 本…...
BUUCTF [羊城杯 2020]easyre 题解
一.查壳 64位无壳 二.主函数逻辑 可以得知flag长度为38,然后进行三次加密 第一次加密是base64加密,得到code1 第二次加密是将code1拆成四段赋给code2 第三次加密是将code2内的数字和字母移3位,其他字符不变 str2保存的是最终的加密字符 三.encode_one_base64 看到主函数…...
网络协议(十二):HTTPS(SSL/TLS、TLS1.2的连接)
网络协议系列文章 网络协议(一):基本概念、计算机之间的连接方式 网络协议(二):MAC地址、IP地址、子网掩码、子网和超网 网络协议(三):路由器原理及数据包传输过程 网络协议(四):网络分类、ISP、上网方式、公网私网、NAT 网络…...
九九乘法表--课后程序(Python程序开发案例教程-黑马程序员编著-第3章-课后作业)
实例9:九九乘法表 乘法口诀是中国古代筹算中进行乘法、除法、开方等运算的基本计算规则,沿用至今已有两千多年。古代的乘法口诀与现在使用的乘法口诀顺序相反,自上而下从“九九八十一”开始到“一一如一”为止,因此,古…...
在超算上安装文件树命令tree
超算平台使用的centos系统没有内置tree命令,需要通过源码安装。记录安装流程如下。 1. 下载源码包 下载链接如下: http://mama.indstate.edu/users/ice/tree/ 选择“Download the latest version” 如本文下载了源码包“tree-2.1.0.tgz”. 2. 源码包…...
论文投稿指南——中文核心期刊推荐(经济管理)
【前言】 🚀 想发论文怎么办?手把手教你论文如何投稿!那么,首先要搞懂投稿目标——论文期刊 🎄 在期刊论文的分布中,存在一种普遍现象:即对于某一特定的学科或专业来说,少数期刊所含…...
在vue中如果computed属性是一个异步操作怎么办?
在计算属性中使用异步方法时,可以使用async/await来处理异步操作。由于计算属性是基于它们的依赖缓存的,所以我们需要使用一个返回Promise的异步方法来确保计算属性能够正常运行。 下面是一个简单的示例,演示如何在计算属性中使用异步方法&am…...
SRP合批问题
1)SRP合批问题 2)多个Base相机渲染到同一个渲染目标,移动平台花屏的问题 3)粒子系统对GPU Instancing的支持 4)如何修改URP下场景和UI分辨率分离(不需要改颜色空间) 这是第327篇UWA技术知识分…...
蓝牙5.1低功耗SOC 私有协议2.4GHz芯片HS6621
HS6621CxC是一个优化功耗真正芯片系统(SOC)解决方案,适用于蓝牙低功耗和私有的2.4GHz应用场景。它集成了一个高性能、小功率的射频收发器,具有蓝牙基带和丰富的外围IO扩展。还集成了电源管理,以提供高效的电源管理。 …...
数据库连接池
数据库连接---执行完毕---释放 连接--释放 十分浪费系统资源 池化技术:准备一些预先的资源,过来就连接预先准备好的 最小连接数: 10 最大连接数:15 业务最高承载上限 排队等待, 等待超时:100…...
Arrays-sort-的用法
1.集合交换元素 Collections.swap(List<?> list, int i, int j); 源码: /*** Swaps the elements at the specified positions in the specified list.* (If the specified positions are equal, invoking this method …...
华为OD机试真题Java实现【寻找相同子串】真题+解题思路+代码(20222023)
寻找相同子串 题目 给你两个字符串 t 和 p ,要求从 t 中找到一个和 p 相同的连续子串,并输出该字串第一个字符的下标。 🔥🔥🔥🔥🔥👉👉👉👉👉👉 华为OD机试(Java)真题目录汇总 输入描述: 输入文件包括两行,分别表示字符串 t 和 p ,保证 t 的长度…...
性能指标 确定性能目标 性能场景设计
性能测试指标 性能测试指标分为业务技术指标和系统资源指标,在服务端性能业务技术指标中分为三个指标,系统吞吐量,响应时间和并发用户数。响应时间分为前端展现时间和系统响应时间两部分,系统吞吐量体现软件系统负载承受能力的指…...
ENVI_Classic:快速入门_菜单栏常见功能的基本介绍
说明:由于实验要求,所以并没有对各个功能进行详尽的解释,大多点到为止,少部分实验内容是实验要求所以步骤详尽。当然由于经验不足,有一些可能存在错误恳请指正.1. 实验目的通过ENVI Classic对自行下载的遥感图像进行一…...
【深度探讨】公共部门在选择区块链平台时要考虑的6个方面
发表时间:2022年8月17日 信息来源:bsvblockchain.org 与私营企业相比,全球的公共部门组织在考虑升级软件解决方案时面临着一系列的全新挑战。公共部门的决策流程冗长而复杂,他们要不惜一切代价避免对现有业务造成干扰,…...
基于阿里云物联网平台设计的实时图传系统_采用MQTT协议传输图像
一、项目功能介绍 当前基于MQTT协议设计了一个实时图传系统,通过这个项目来演示,两个MQTT设备如何互相订阅,进行消息流转。 在阿里云服务器上创建2个设备,分为为设备A和设备B;设备A负责采集本地摄像头画面上传,设备B负责接收设备A上传的数据然后解析显示出来。在阿里云服…...
42-Golang中的单元测试
Golang中的单元测试需求传统方法基本介绍单元测试快速入门总结综合案例需求 在工作中,我们会遇到这样的情况,就是去确认一个函数,或者一个模块的结果是否正确 传统方法 在main函数中,调用addUpper函数,看看实际输出…...
python实现k_means聚类
K-Means算法是将一组N个样本的特征矩阵X划分为K个无交集的簇,直观上来看是簇是一组一组聚集在一起的数据,在一个簇中的数据就认为是同一类。簇就是聚类的结果表现。簇中所有数据的均值通常被称为这个簇的“质心”(Centroids)。在一个二维平面中ÿ…...
【批处理脚本】-3.3-exit命令详解
"><--点击返回「批处理BAT从入门到精通」总目录--> 共3页精讲(列举了所有exit的用法,图文并茂,通俗易懂) 在从事“嵌入式软件开发”和“Autosar工具开发软件”过程中,经常会在其集成开发环境IDE(CodeWarrior,S32K DS,Davinci,EB Tresos,ETAS…)中,…...
闵行网站制作/seo服务的内容
原标题:在Linux右键菜单里添加文件对比快捷方式要在Linux系统的右键菜单中添加文件对比的快捷方式,可以通过文件对比工具Beyond Compare来完成,具体方法如下。1、首先,请确保安装了最新版本的Beyond CompareBeyond Compare下载&am…...
邯郸论坛网站建设/网站推广郑州
零基础学黑客,搜索公众号:白帽子左一作者:admmin 因为BurpSuite需要在Java环境下运行,所以安装BurpSuite之前需要配置好Java环境。 我这里就直接给大家打包好java15版本的了, 已经是java15的可以不用安装 , 不是java15版本或者j…...
住房和建设局网站/世界疫情最新数据
前言:在数据库开发过程中我们经常会使用分页,核心技术是使用用limit start, count分页语句进行数据的读取。 一、MySQL分页起点越大查询速度越慢 直接用limit start, count分页语句,表示从第start条记录开始选择count条记录 : …...
网站ftp有什么用/互联网广告精准营销
一、位操作符: & //按位与 | //按位或 ^ //按位异或注意:它们的操作数必须是整数。 二、计算规则 示例一:按位与& int main() {int a 3;int b 5;//& - 按(二进制)位与int c a &…...
南昌企业建站系统/云盘网页版登录
考研复试系列——第七节 最短路径 前言 前面我们学习了DFS算法,利用DFS算法,我们以每一个顶点为开始节点进行DFS,最后进行比较也可以求得最短路径,但是复杂度不能满足我们的需求。现在我们通过Floyd算法和Dijkstra算法来解决最短…...
在哪个网站可做网络夫妻/产品怎么做推广和宣传
为了做图像处理,须要用摄像头,搜到实验室仅仅有一个摄像头,是国安的。详细參数在终端中看到: 本来操心这个摄像头在6410中能不能用,结果插上后得到如上显示,知道该摄像头是uvc的。可用。參考文章链接&#…...