前端【9种前端常见的设计模式】
🌟9种前端常见的设计模式
哈喽小伙伴们,这期给大家整理了一些有关9种前端常见的设计模式,覆盖多方面基础知识,建议大家收藏阅读。
文章目录
- 🌟9种前端常见的设计模式
- 🌟1. 外观模式
- 🌟 2. 代理模式
- 🌟3. 工厂模式
- 🌟 4. 单例模式
- 🌟5. 策略模式
- 🌟6. 迭代器模式
- 🌟 7. 观察者模式
- 🌟8. 中介者模式
- 🌟 9. 访问者模式
- 🌟写在最后
- 🌟JSON包里写函数,关注博主不迷路
🌟1. 外观模式
外观模式是最常见的设计模式之一,它为子系统中的一组接口提供一个统一的高层接口,使子系统更容易使用。简而言之外观设计模式就是把多个子系统中复杂逻辑进行抽象,从而提供一个更统一、更简洁、更易用的API。很多我们常用的框架和库基本都遵循了外观设计模式,比如JQuery就把复杂的原生DOM操作进行了抽象和封装,并消除了浏览器之间的兼容问题,从而提供了一个更高级更易用的版本。其实在平时工作中我们也会经常用到外观模式进行开发,只是我们不自知而已
兼容浏览器事件绑定
let addMyEvent = function (el, ev, fn) {if (el.addEventListener) {el.addEventListener(ev, fn, false)} else if (el.attachEvent) {el.attachEvent('on' + ev, fn)} else {el['on' + ev] = fn}
};
封装接口
let myEvent = {// ...stop: e => {e.stopPropagation();e.preventDefault();}
};
场景
- 设计初期,应该要有意识地将不同的两个层分离,比如经典的三层结构,在数据访问层和业务逻辑层、业务逻辑层和表示层之间建立外观Facade
- 在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂,增加外观Facade可以提供一个简单的接口,减少他们之间的依赖。
- 在维护一个遗留的大型系统时,可能这个系统已经很难维护了,这时候使用外观Facade也是非常合适的,为系系统开发一个外观Facade类,为设计粗糙和高度复杂的遗留代码提供比较清晰的接口,让新系统和Facade对象交互,Facade与遗留代码交互所有的复杂工作。
优点
- 减少系统相互依赖。
- 提高灵活性。
- 提高了安全性
缺点
不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。
🌟 2. 代理模式
是为一个对象提供一个代用品或占位符,以便控制对它的访问
假设当A 在心情好的时候收到花,小明表白成功的几率有60%,而当A 在心情差的时候收到花,小明表白的成功率无限趋近于0。小明跟A 刚刚认识两天,还无法辨别A 什么时候心情好。如果不合时宜地把花送给A,花被直接扔掉的可能性很大,这束花可是小明吃了7 天泡面换来的。但是A 的朋友B 却很了解A,所以小明只管把花交给B,B 会监听A 的心情变化,然后选择A 心情好的时候把花转交给A,代码如下:
let Flower = function() {}
let xiaoming = {sendFlower: function(target) {let flower = new Flower()target.receiveFlower(flower)}
}
let B = {receiveFlower: function(flower) {A.listenGoodMood(function() {A.receiveFlower(flower)})}
}
let A = {receiveFlower: function(flower) {console.log('收到花'+ flower)},listenGoodMood: function(fn) {setTimeout(function() {fn()}, 1000)}
}
xiaoming.sendFlower(B)
场景
HTML元 素事件代理
<ul id="ul"><li>1</li><li>2</li><li>3</li>
</ul>
<script>let ul = document.querySelector('#ul');ul.addEventListener('click', event => {console.log(event.target);});
</script>
优点
- 代理模式能将代理对象与被调用对象分离,降低了系统的耦合度。代理模式在客户端和目标对象之间起到一个中介作用,这样可以起到保护目标对象的作用
- 代理对象可以扩展目标对象的功能;通过修改代理对象就可以了,符合开闭原则;
缺点
处理请求速度可能有差别,非直接访问存在开销
🌟3. 工厂模式
工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式使一个类的实例化延迟到了子类。而子类可以重写接口方法以便创建的时候指定自己的对象类型。
class Product {constructor(name) {this.name = name}init() {console.log('init')}fun() {console.log('fun')}
}class Factory {create(name) {return new Product(name)}
}// use
let factory = new Factory()
let p = factory.create('p1')
p.init()
p.fun()
场景
- 如果你不想让某个子系统与较大的那个对象之间形成强耦合,而是想运行时从许多子系统中进行挑选的话,那么工厂模式是一个理想的选择
- 将new操作简单封装,遇到new的时候就应该考虑是否用工厂模式;
- 需要依赖具体环境创建不同实例,这些实例都有相同的行为,这时候我们可以使用工厂模式,简化实现的过程,同时也可以减少每种对象所需的代码量,有利于消除对象间的耦合,提供更大的灵活性
优点
- 创建对象的过程可能很复杂,但我们只需要关心创建结果。
- 构造函数和创建者分离, 符合“开闭原则”
- 一个调用者想创建一个对象,只要知道其名称就可以了。
- 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
缺点
- 添加新产品时,需要编写新的具体产品类,一定程度上增加了系统的复杂度
- 考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度
什么时候不用
当被应用到错误的问题类型上时,这一模式会给应用程序引入大量不必要的复杂性.除非为创建对象提供一个接口是我们编写的库或者框架的一个设计上目标,否则我会建议使用明确的构造器,以避免不必要的开销。
由于对象的创建过程被高效的抽象在一个接口后面的事实,这也会给依赖于这个过程可能会有多复杂的单元测试带来问题。
🌟 4. 单例模式
顾名思义,单例模式中Class的实例个数最多为1。当需要一个对象去贯穿整个系统执行某些任务时,单例模式就派上了用场。而除此之外的场景尽量避免单例模式的使用,因为单例模式会引入全局状态,而一个健康的系统应该避免引入过多的全局状态。
实现单例模式需要解决以下几个问题:
- 如何确定Class只有一个实例?
- 如何简便的访问Class的唯一实例?
- Class如何控制实例化的过程?
- 如何将Class的实例个数限制为1?
我们一般通过实现以下两点来解决上述问题:
- 隐藏Class的构造函数,避免多次实例化
- 通过暴露一个
getInstance()
方法来创建/获取唯一实例
Javascript中单例模式可以通过以下方式实现:
// 单例构造器
const FooServiceSingleton = (function () {// 隐藏的Class的构造函数function FooService() {}// 未初始化的单例对象let fooService;return {// 创建/获取单例对象的函数getInstance: function () {if (!fooService) {fooService = new FooService();}return fooService;}}
})();
实现的关键点有:
- 使用 IIFE创建局部作用域并即时执行;
- getInstance() 为一个 闭包 ,使用闭包保存局部作用域中的单例对象并返回。
我们可以验证下单例对象是否创建成功:
const fooService1 = FooServiceSingleton.getInstance();
const fooService2 = FooServiceSingleton.getInstance();console.log(fooService1 === fooService2); // true
场景例子
- 定义命名空间和实现分支型方法
- 登录框
- vuex 和 redux中的store
优点
- 划分命名空间,减少全局变量
- 增强模块性,把自己的代码组织在一个全局变量名下,放在单一位置,便于维护
- 且只会实例化一次。简化了代码的调试和维护
缺点
- 由于单例模式提供的是一种单点访问,所以它有可能导致模块间的强耦合
- 从而不利于单元测试。无法单独测试一个调用了来自单例的方法的类,而只能把它与那个单例作为一 个单元一起测试。
🌟5. 策略模式
策略模式简单描述就是:对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。把它们一个个封装起来,并且使它们可以互相替换
<html>
<head><title>策略模式-校验表单</title><meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body><form id = "registerForm" method="post" action="http://xxxx.com/api/register">用户名:<input type="text" name="userName">密码:<input type="text" name="password">手机号码:<input type="text" name="phoneNumber"><button type="submit">提交</button></form><script type="text/javascript">// 策略对象const strategies = {isNoEmpty: function (value, errorMsg) {if (value === '') {return errorMsg;}},isNoSpace: function (value, errorMsg) {if (value.trim() === '') {return errorMsg;}},minLength: function (value, length, errorMsg) {if (value.trim().length < length) {return errorMsg;}},maxLength: function (value, length, errorMsg) {if (value.length > length) {return errorMsg;}},isMobile: function (value, errorMsg) {if (!/^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|17[7]|18[0|1|2|3|5|6|7|8|9])\d{8}$/.test(value)) {return errorMsg;} }}// 验证类class Validator {constructor() {this.cache = []}add(dom, rules) {for(let i = 0, rule; rule = rules[i++];) {let strategyAry = rule.strategy.split(':')let errorMsg = rule.errorMsgthis.cache.push(() => {let strategy = strategyAry.shift()strategyAry.unshift(dom.value)strategyAry.push(errorMsg)return strategies[strategy].apply(dom, strategyAry)})}}start() {for(let i = 0, validatorFunc; validatorFunc = this.cache[i++];) {let errorMsg = validatorFunc()if (errorMsg) {return errorMsg}}}}// 调用代码let registerForm = document.getElementById('registerForm')let validataFunc = function() {let validator = new Validator()validator.add(registerForm.userName, [{strategy: 'isNoEmpty',errorMsg: '用户名不可为空'}, {strategy: 'isNoSpace',errorMsg: '不允许以空白字符命名'}, {strategy: 'minLength:2',errorMsg: '用户名长度不能小于2位'}])validator.add(registerForm.password, [ {strategy: 'minLength:6',errorMsg: '密码长度不能小于6位'}])validator.add(registerForm.phoneNumber, [{strategy: 'isMobile',errorMsg: '请输入正确的手机号码格式'}])return validator.start()}registerForm.onsubmit = function() {let errorMsg = validataFunc()if (errorMsg) {alert(errorMsg)return false}}</script>
</body>
</html>
场景例子
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的’行为’,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种。
- 表单验证
优点
- 利用组合、委托、多态等技术和思想,可以有效的避免多重条件选择语句
- 提供了对开放-封闭原则的完美支持,将算法封装在独立的strategy中,使得它们易于切换,理解,易于扩展
- 利用组合和委托来让Context拥有执行算法的能力,这也是继承的一种更轻便的代替方案
缺点
- 会在程序中增加许多策略类或者策略对象
- 要使用策略模式,必须了解所有的strategy,必须了解各个strategy之间的不同点,这样才能选择一个合适的strategy
🌟6. 迭代器模式
如果你看到这,ES6中的迭代器 Iterator 相信你还是有点印象的,上面第60条已经做过简单的介绍。迭代器模式简单的说就是提供一种方法顺序一个聚合对象中各个元素,而又不暴露该对象的内部表示。
迭代器模式解决了以下问题:
- 提供一致的遍历各种数据结构的方式,而不用了解数据的内部结构
- 提供遍历容器(集合)的能力而无需改变容器的接口
一个迭代器通常需要实现以下接口:
- hasNext():判断迭代是否结束,返回Boolean
- next():查找并返回下一个元素
为Javascript的数组实现一个迭代器可以这么写:
const item = [1, 'red', false, 3.14];function Iterator(items) {this.items = items;this.index = 0;
}Iterator.prototype = {hasNext: function () {return this.index < this.items.length;},next: function () {return this.items[this.index++];}
}
验证一下迭代器是否工作:
const iterator = new Iterator(item);while(iterator.hasNext()){console.log(iterator.next());
}
//输出:1, red, false, 3.14
ES6提供了更简单的迭代循环语法 for…of,使用该语法的前提是操作对象需要实现 可迭代协议(The iterable protocol),简单说就是该对象有个Key为 Symbol.iterator 的方法,该方法返回一个iterator对象。
比如我们实现一个 Range 类用于在某个数字区间进行迭代:
function Range(start, end) {return {[Symbol.iterator]: function () {return {next() {if (start < end) {return { value: start++, done: false };}return { done: true, value: end };}}}}
}
验证一下:
for (num of Range(1, 5)) {console.log(num);
}
// 输出:1, 2, 3, 4
🌟 7. 观察者模式
观察者模式又称发布-订阅模式(Publish/Subscribe Pattern),是我们经常接触到的设计模式,日常生活中的应用也比比皆是,比如你订阅了某个博主的频道,当有内容更新时会收到推送;又比如JavaScript中的事件订阅响应机制。观察者模式的思想用一句话描述就是:被观察对象(subject)维护一组观察者(observer),当被观察对象状态改变时,通过调用观察者的某个方法将这些变化通知到观察者。
观察者模式中Subject对象一般需要实现以下API:
- subscribe(): 接收一个观察者observer对象,使其订阅自己
- unsubscribe(): 接收一个观察者observer对象,使其取消订阅自己
- fire(): 触发事件,通知到所有观察者
用JavaScript手动实现观察者模式:
// 被观察者
function Subject() {this.observers = [];
}Subject.prototype = {// 订阅subscribe: function (observer) {this.observers.push(observer);},// 取消订阅unsubscribe: function (observerToRemove) {this.observers = this.observers.filter(observer => {return observer !== observerToRemove;})},// 事件触发fire: function () {this.observers.forEach(observer => {observer.call();});}
}
验证一下订阅是否成功:
const subject = new Subject();function observer1() {console.log('Observer 1 Firing!');
}function observer2() {console.log('Observer 2 Firing!');
}subject.subscribe(observer1);
subject.subscribe(observer2);
subject.fire();//输出:
Observer 1 Firing!
Observer 2 Firing!
验证一下取消订阅是否成功:
subject.unsubscribe(observer2);
subject.fire();//输出:
Observer 1 Firing!
场景
- DOM事件
document.body.addEventListener('click', function() {console.log('hello world!');
});
document.body.click()
- vue 响应式
优点
- 支持简单的广播通信,自动通知所有已经订阅过的对象
- 目标对象与观察者之间的抽象耦合关系能单独扩展以及重用
- 增加了灵活性
- 观察者模式所做的工作就是在解耦,让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响到另一边的变化。
缺点
过度使用会导致对象与对象之间的联系弱化,会导致程序难以跟踪维护和理解
🌟8. 中介者模式
- 在中介者模式中,中介者(Mediator)包装了一系列对象相互作用的方式,使得这些对象不必直接相互作用,而是由中介者协调它们之间的交互,从而使它们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用,保证这些作用可以彼此独立的变化。
- 中介者模式和观察者模式有一定的相似性,都是一对多的关系,也都是集中式通信,不同的是中介者模式是处理同级对象之间的交互,而观察者模式是处理Observer和Subject之间的交互。中介者模式有些像婚恋中介,相亲对象刚开始并不能直接交流,而是要通过中介去筛选匹配再决定谁和谁见面。
场景
例如购物车需求,存在商品选择表单、颜色选择表单、购买数量表单等等,都会触发change事件,那么可以通过中介者来转发处理这些事件,实现各个事件间的解耦,仅仅维护中介者对象即可。
var goods = { //手机库存'red|32G': 3,'red|64G': 1,'blue|32G': 7,'blue|32G': 6,
};
//中介者
var mediator = (function() {var colorSelect = document.getElementById('colorSelect');var memorySelect = document.getElementById('memorySelect');var numSelect = document.getElementById('numSelect');return {changed: function(obj) {switch(obj){case colorSelect://TODObreak;case memorySelect://TODObreak;case numSelect://TODObreak;}}}
})();
colorSelect.onchange = function() {mediator.changed(this);
};
memorySelect.onchange = function() {mediator.changed(this);
};
numSelect.onchange = function() {mediator.changed(this);
};
- 聊天室里
聊天室成员类:
function Member(name) {this.name = name;this.chatroom = null;
}Member.prototype = {// 发送消息send: function (message, toMember) {this.chatroom.send(message, this, toMember);},// 接收消息receive: function (message, fromMember) {console.log(`${fromMember.name} to ${this.name}: ${message}`);}
}
聊天室类:
function Chatroom() {this.members = {};
}Chatroom.prototype = {// 增加成员addMember: function (member) {this.members[member.name] = member;member.chatroom = this;},// 发送消息send: function (message, fromMember, toMember) {toMember.receive(message, fromMember);}
}
测试一下:
const chatroom = new Chatroom();
const bruce = new Member('bruce');
const frank = new Member('frank');chatroom.addMember(bruce);
chatroom.addMember(frank);bruce.send('Hey frank', frank);//输出:bruce to frank: hello frank
优点
- 使各对象之间耦合松散,而且可以独立地改变它们之间的交互
- 中介者和对象一对多的关系取代了对象之间的网状多对多的关系
- 如果对象之间的复杂耦合度导致维护很困难,而且耦合度随项目变化增速很快,就需要中介者重构代码
缺点
系统中会新增一个中介者对象,因为对象之间交互的复杂性,转移成了中介者对象的复杂性,使得中介者对象经常是巨大的。中介 者对象自身往往就是一个难以维护的对象。
🌟 9. 访问者模式
访问者模式 是一种将算法与对象结构分离的设计模式,通俗点讲就是:访问者模式让我们能够在不改变一个对象结构的前提下能够给该对象增加新的逻辑,新增的逻辑保存在一个独立的访问者对象中。访问者模式常用于拓展一些第三方的库和工具。
// 访问者
class Visitor {constructor() {}visitConcreteElement(ConcreteElement) {ConcreteElement.operation()}
}
// 元素类
class ConcreteElement{constructor() {}operation() {console.log("ConcreteElement.operation invoked"); }accept(visitor) {visitor.visitConcreteElement(this)}
}
// client
let visitor = new Visitor()
let element = new ConcreteElement()
elementA.accept(visitor)
访问者模式的实现有以下几个要素:
- Visitor Object:访问者对象,拥有一个visit()方法
- Receiving Object:接收对象,拥有一个 accept() 方法
- visit(receivingObj):用于Visitor接收一个Receiving Object
- accept(visitor):用于Receving Object接收一个Visitor,并通过调用Visitor的 visit() 为其提供获取Receiving Object数据的能力
简单的代码实现如下:
Receiving Object:function Employee(name, salary) {this.name = name;this.salary = salary;
}Employee.prototype = {getSalary: function () {return this.salary;},setSalary: function (salary) {this.salary = salary;},accept: function (visitor) {visitor.visit(this);}
}
Visitor Object:function Visitor() { }Visitor.prototype = {visit: function (employee) {employee.setSalary(employee.getSalary() * 2);}
}
验证一下:
const employee = new Employee('bruce', 1000);
const visitor = new Visitor();
employee.accept(visitor);console.log(employee.getSalary());//输出:2000
场景
对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作
需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。
优点
- 符合单一职责原则
- 优秀的扩展性
- 灵活性
缺点
- 具体元素对访问者公布细节,违反了迪米特原则
- 违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
- 具体元素变更比较困难
🌟写在最后
有不懂的地方或者需要帮助的,请添加文末的个人VX, 愿为各位小伙伴解答
🌟JSON包里写函数,关注博主不迷路
✨原创不易,还希望各位大佬支持一下!
👍 点赞,你的认可是我创作的动力!
⭐️ 收藏,你的青睐是我努力的方向!
✏️ 评论,你的意见是我进步的财富!
相关文章:
前端【9种前端常见的设计模式】
🌟9种前端常见的设计模式 哈喽小伙伴们,这期给大家整理了一些有关9种前端常见的设计模式,覆盖多方面基础知识,建议大家收藏阅读。 文章目录 🌟9种前端常见的设计模式🌟1. 外观模式🌟 2. 代理模…...
IDEA使用HotSwapHelper进行热部署
目录 前言JDK1.8特殊准备DECVM安装插件安装与配置参考文档相关下载 前言 碰到了一个项目,用jrebel启动项目时一直报错,不用jrebel时又没问题,找不到原因,又不想放弃热部署功能 因此思考能否通过其他方式进行热部署,找…...
【Django-xadmin】
时间长不用,会忘的系列 1、Django-xadmin后台字段显示处理 主要是修改每个模块下adminx.py文件 代码解释:第1行控制表单字段显示第2行控制列表字段显示第3行控制搜索条件第4行控制过滤条件第5行支持单个或多个字段信息修改第6行列表分页,每页显示多少行…...
AI 计算基础设施的战略转折点分析
核心技术范式转移 我们正处于计算架构的重大转折点。第一个根本性转变是从传统的 CPU 编程范式,向以 GPU 为核心的神经网络运算模式转移。这不仅仅是硬件架构的改变,更代表了整个软件开发和应用部署方式的革新。第二个转变则是在这个新的基础设施之上&a…...
Java基于SpringBoot+Vue的IT技术交流和分享平台(附源码+lw+部署)
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
二:OpenStack环境准备-controller node
一:工具、环境准备-controller node 二:OpenStack环境准备-controller node 三:安装服务-controller node 四:工具、环境准备-compute node 五:OpenStack环境准备-compute node 六:安装服务-compute node 七…...
解决stable-diffusion-webui时的问题:No module ‘xformers‘. Proceeding without it
p.s 被另一篇文章坑了,装个xformers把我原先的pytorch降智了&%$^# 注意:!!!xformers非强制安装;可优化显存,提高性能和出图速率,对于GPU能力有限的用户很有用;安装过…...
清理Linux/CentOS7根目录的思路
在使用Linux服务器过程中,经常会遇到磁盘空间不足的问题,好多应用默认安装在根目录下,记录一下如何找到问题所在,清理根目录(/) 1. 检查空间使用情况 1.1 查看分区占用: df -h输出࿱…...
人工智能-深度学习-BP算法
BP算法的核心思想是通过计算损失函数对网络参数的梯度,然后使用梯度下降法来更新网络参数,从而最小化损失函数。 误差反向传播算法(BP)的基本步骤: 前向传播:正向计算得到预测值。 计算损失:通过损失函数计算预测值和真实值的差…...
C++小问题
怎么分辨const修饰的是谁 是限定谁不能被改变的? 在C中,const关键字的用途和位置非常关键,它决定了谁不能被修改。const可以修饰变量、指针、引用等不同的对象,并且具体的作用取决于const的修饰位置。理解const的规则能够帮助我们…...
如何让控件始终处于父容器的居中位置(父容器可任意改变大小)
前言: 大家好,我是上位机马工,硕士毕业4年年入40万,目前在一家自动化公司担任软件经理,从事C#上位机软件开发8年以上!我们在C#开发winform程序的时候,有时候需要将一个控件居中显示,…...
Python 调用 Umi-OCR API 批量识别图片/PDF文档数据
目录 一、需求分析 二、方案设计(概要/详细) 三、技术选型 四、OCR 测试 Demo 五、批量文件识别完整代码实现 六、总结 一、需求分析 市场部同事进行采购或给客户报价时,往往基于过往采购合同数据,给出现在采购或报价的金额…...
Java基础访问修饰符全解析
一、Java 访问修饰符概述 Java 中的访问修饰符用于控制类、方法、变量和构造函数的可见性和访问权限,主要有四种:public、protected、default(无修饰符)和 private。 Java 的访问修饰符在编程中起着至关重要的作用,它…...
朗迪锋亮相2024人因工程与智能系统交互国际会议
2024年11月28日至30日,2024人因工程与智能系统交互国际会议在深圳隆重举办。此次大会以推动我国人因工程学科发展为目标,致力于加强国际学术交流,深入探讨人工智能时代的智能系统交互,旨在培育新质生产力,助力经济社会…...
OpenGL学习过程总结
1、矩阵 参考链接 第三课:矩阵变换...
webGL入门教程_06变换矩阵与绕轴旋转总结
变换矩阵与绕轴旋转总结 目录 1. 变换矩阵简介2. 平移矩阵3. 缩放矩阵4. 旋转矩阵 4.1 绕 Z 轴旋转4.2 绕 X 轴旋转4.3 绕 Y 轴旋转 5. 组合变换矩阵6. 结论 1. 变换矩阵简介 在计算机图形学中,变换矩阵用于在三维空间中对物体进行操作,包括ÿ…...
mysql 查询所有的触发器
SELECTTRIGGER_SCHEMA AS Database,TRIGGER_NAME AS Trigger,EVENT_OBJECT_TABLE AS Table,EVENT_MANIPULATION AS Event,ACTION_STATEMENT AS Statement FROMinformation_schema.TRIGGERS;创建触发器遇到报错: You do not have the SUPER privilege and binary lo…...
基于Java Springboot个人财务APP且微信小程序
一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术:Html、Css、Js、Vue、Element-ui 数据库:MySQL 后端技术:Java、Spring Boot、MyBatis 三、运行环境 开发工具:IDEA/eclipse 微信…...
GateWay使用手册
好的,下面是优化后的版本。为了提高可读性和规范性,我对内容进行了结构化、简化了部分代码,同时增加了注释说明,便于理解。 1. 引入依赖 在 pom.xml 中添加以下依赖: <dependencies><!-- Spring Cloud Gate…...
go语言读取yaml配置文件内容
1、config.yaml配置文件内容假设如下 name: "example" version: 1.0 settings:timeout: 30debug: truefeatures:- feature1- feature22、定义结构体 go语言定义结构体匹配yaml内容 package mainimport ("fmt""log""os""gopkg.…...
Proteus8.17下载安装教程
Proteus是一款嵌入式系统仿真开发软件,实现了从原理图设计、单片机编程、系统仿真到PCB设计,真正实现了从概念到产品的完整设计,其处理器模型支持8051、HC11、PIC10/12/16/18/24/30/DsPIC33、AVR、ARM、8086和MSP430等,能够帮助用…...
【AI】Sklearn
长期更新,建议关注、收藏、点赞。 友情链接: AI中的数学_线代微积分概率论最优化 Python numpy_pandas_matplotlib_spicy 建议路线:机器学习->深度学习->强化学习 目录 预处理模型选择分类实例: 二分类比赛 网格搜索实例&…...
图数据库 | 10、图数据库架构设计——高性能图存储架构(上)
老夫在之前的三大篇内容中,介绍了图数据库的三大组件—图计算、图存储以及图查询语言。(都归拢在图数据库原理、架构与应用这个专栏中了,感兴趣的朋友可以在去找阅读。) 接下来,老夫还将继续深化这三大组件࿰…...
el-table 组件二次封装(vue2)
PublicTable.vue <!-- 公共表格组件 --> <template><div class"table-common"><el-table v-loading"loading" :ref"tableid" border style"width: 100%" :data"tableDatas" :row-key"rowKey&quo…...
张量并行和流水线并行在Transformer中的具体部位
目录 张量并行和流水线并行在Transformer中的具体部位 一、张量并行 二、流水线并行 张量并行和流水线并行在Transformer中的具体部位 张量并行和流水线并行是Transformer模型中用于提高训练效率的两种并行策略。它们分别作用于模型的不同部位,以下是对这两种并行的具体说…...
详解Qt pdf 之QPdfSelection 选择文本类
文章目录 QPdfSelection 类详解前言 详细说明公共函数说明1. 构造函数2. text3. boundingRect4. isEmpty5. startPage6. endPage 使用场景示例代码代码说明总结 QPdfSelection 类详解 前言 QPdfSelection 是 Qt PDF 模块中的一个类,用于表示在 PDF 文档中被选中的…...
一款支持80+语言,包括:拉丁文、中文、阿拉伯文、梵文等开源OCR库
大家好,今天给大家分享一个基于PyTorch的OCR库EasyOCR,它允许开发者通过简单的API调用来读取图片中的文本,无需复杂的模型训练过程。 项目介绍 EasyOCR 是一个基于Python的开源项目,它提供了一个简单易用的光学字符识别ÿ…...
matlab 中的 bug
在matlab中绘图,设置 axe 的背景颜色 axes_in3.Color #00235B ;打印的时候 print(figure_handle1,-dpng,-r300,"merge_yt_ey") ;此时保存的图片无法识别背景颜色 原因在于 matlab 中的 InverseHardcopy 将 InvertHardcopy 设置成 off 则可以解决这个问…...
【算法刷题指南】优先级队列
🌈个人主页: 南桥几晴秋 🌈C专栏: 南桥谈C 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据…...
android user版本默认usb模式为充电模式
android插入usb时会切换至默认设置的模式,debug版本为adb,user版本为mtp protected long getChargingFunctions() {// if ADB is enabled, reset functions to ADB// else enable MTP as usual.if (isAdbEnabled()) {return UsbManager.FUNCTION_ADB;} e…...
[极客大挑战 2019]HardSQL--详细解析
信息搜集 登录系统,有两个可能的注入点: 随便输一下看看传参类型: 都是GET型。 SQL注入 传参 usernameadmin’&password123 传参 usernameadmin&password123’ username和password传参,四种闭合方式只有单引号报错&a…...
java基础概念46-数据结构1
一、引入 List集合的三种实现类使用了不同的数据结构! 二、数据结构的定义 三、常见的数据结构 3-1、栈 特点:先进后出,后进先出。 java内存容器: 3-2、队列 特点:先进先出、后进后出。 栈VS队列-小结 3-3、数组 3-…...
数学建模选MATLAB还是Python?
在进行数学建模时,选择合适的编程语言和工具对于建模的效率和效果至关重要。目前,MATLAB和Python是两个常用的数学建模工具,它们各自有优缺点,适用于不同的场景。本文将从多个维度对MATLAB和Python进行比较,帮助大家做…...
【C++】多线程
目录 一 概念 1 多线程 2 多进程与多线程 3 多线程理解 二 创建线程 1 thread 2 join() 和 detach() 3 this_thread 三 std::mutex 1 lock 和 unlock 2 lock_guard 3 unique_lock 四 condition_variable 五 std::atomic 一 概念 1 多线程 在C11之前࿰…...
【计算机网络】实验2:总线型以太网的特性
实验 2:总线型以太网的特性 一、 实验目的 加深对MAC地址,IP地址,ARP协议的理解。 了解总线型以太网的特性(广播,竞争总线,冲突)。 二、 实验环境 • Cisco Packet Tracer 模拟器 三、 实…...
基于Matlab合成孔径雷达(SAR)回波信号建模与多指标质量评估
本研究基于合成孔径雷达(SAR)技术,建立了一个雷达回波信号的模拟模型,并通过多项评价指标对信号质量进行深入评估。首先,研究定义了与SAR系统相关的关键物理参数,如工作频率、平台速度、脉冲宽度、采样率等…...
spring boot3.3.5 logback-spring.xml 配置
新建 resources/logback-spring.xml 控制台输出颜色有点花 可以自己更改 <?xml version"1.0" encoding"UTF-8"?> <!--关闭文件扫描 scanfalse --> <configuration debug"false" scan"false"><springProperty …...
浅谈C#库之DevExpress
一、DevExpress库介绍 DevExpress是一个功能强大、界面美观的UI组件库,广泛应用于桌面应用程序和Web应用程序的开发中。它提供了丰富的控件和工具,帮助开发人员快速构建现代化的用户界面。DevExpress控件库以其功能丰富、应用简便、界面华丽以及方便定制…...
【webApp之h5端实战】项目基础结构搭建及欢迎页面的实现
这是一个实战项目的webapp,主要是使用原生js/css/html来实现我们的业务。预览下面的实战效果,我们将会从0到1实现这个系列的项目。包括大量的原生js知识,css3动画的开发,以及页面的交互实现。 效果预览 项目准备工作 封装的工具类,用于获取原生dom节点,处理原生dom事件的…...
生成树详解(STP、RSTP、MSTP)
目录 1、STP 1.概述 2.基本概念 3.端口角色及其作用 4.报文结构 5.STP的端口状态 6.三种定时器 7.STP选举步骤 8.配置BPDU的比较原则 9.TCN BPDU 10.临时环路的问题 11.传统STP的不足 拓扑变更处理过程 2、RSTP 1.端口角色 2.端口状态 3.P/A(Propo…...
C++趣味编程:基于树莓派Pico的模拟沙漏-倾斜开关与LED的互动实现
沙漏,作为一种古老的计时工具,利用重力让沙子通过狭小通道,形成了计时效果。在现代,我们可以通过电子元件模拟沙漏的工作原理。本项目利用树莓派Pico、倾斜开关和LED,实现了一个电子沙漏。以下是项目的详细技术解析与C++代码实现。 一、项目概述 1. 项目目标 通过倾斜开关…...
Matlab Simulink 电力电子仿真-单相电压型半桥逆变电路分析
目录 一、单相电压型半桥逆变电路仿真模型 1.电路模型 2.电路模型参数 二、仿真分析 三、总结 1.优缺点 2.应用场景 一、单相电压型半桥逆变电路仿真模型 1.电路模型 单相电压型半桥逆变电路是一种常见的逆变电路,主要用于将直流电源转换为交流电源。 &…...
在超表面中琼斯矩阵的使用
琼斯矩阵(Jones Matrix) 是一种线性代数方法,用于描述光的偏振状态和偏振变化,是偏振光学中重要的数学工具。它在 超表面理论设计 中广泛应用,尤其是在设计和调控光与物质相互作用时,例如偏振控制、相位调制…...
threeJs学习 贴图 :地球
效果图: 贴图以后的效果: vue代码: <template><div class"scene_box"><p>创建纹理贴图TextureLoader</p><div class"canvas"></div></div> </template><script s…...
详解Rust多线程编程
文章目录 多线程模型创建和管理线程自定义线程行为线程传递数据线程间通信线程池错误处理与线程Condvar(条件变量)无锁并发高性能并发库 Rust的多线程编程提供了一种安全、高效的方式来进行并发操作。Rust的并发性设计原则之一是确保线程安全,同时避免运行时的开销&…...
Uniapp触底刷新
在你的代码中,使用了 scroll-view 来实现一个可滚动的评论区域,并且通过监听 scrolltolower 事件来触发 handleScrollToLower 函数,以实现“触底更新”或加载更多评论的功能。 关键部分分析: scroll-view 组件: scroll-view 是一…...
【前端】安装hadoop后,前端启动报错,yarn命令
新安装hadoop后,前端启动项目用yarn命令,报错。 报错:系统找不到指定的路径。 No HADOOP_CONF_DIR set. Please specify it either in yarn-env.cmd or in the environment. 解决:删掉hadoop目录下yarn的文件 检查:…...
T620存储安全方案SoC芯片技术手册
系统资源 集成32位国产CPU CK803S;最高工作频率260Mhz CK803S内置16KB I/D Cache,内置32KB DTCM 32KB ROM;256KB SRAM;8KB SRAM(系统专用) 512KB/1MB 片内Flash 安全算法 支持SM4数据加密,加密性…...
Rust循环引用与多线程并发
循环引用与自引用 循环引用的概念 循环引用指的是两个或多个对象之间相互持有对方的引用。在 Rust 中,由于所有权和生命周期的严格约束,直接创建循环引用通常会导致编译失败。例如: // 错误的循环引用示例 struct Node {next: Option<B…...
力扣 二叉树的锯齿形层序遍历-103
二叉树的锯齿形层序遍历-103 此题就是再二叉树层序遍历的基础上,加了反转当前层数组元素的函数reverse(),也可以不反转,直接在遍历当前层的所有节点的for循环里直接进行if判断,根据遍历方向,决定如何插入元素。 clas…...