提升开发思维的设计模式(上)

1. 设计模式简介

[设计模式](Design pattern) 是解决软件开发某些特定问题而提出的一些解决方案也可以理解成解决问题的一些思路。通过设计模式可以帮助我们增强代码的[可重用性]、可扩充性、 可维护性、灵活性好。我们使用设计模式最终的目的是实现代码的 [高内聚]耦合。通俗一点讲的话 打比方面试官经常会问你如何让代码有健壮性。其实把代码中的变与不变分离,确保变化的部分灵活、不变的部分稳定,这样的封装变化就是代码健壮性的关键。而设计模式的出现,就是帮我们写出这样的代码。 设计模式就是解决编程里某类问题的通用模板,总结出来的代码套路就是设计模式。本文章总结下JS在工作中常用的设计模式 ,以帮助大家提高代码性能,增强工作效率!

设计模式原则

  • S – Single Responsibility Principle 单一职责原则

    • 一个程序只做好一件事

    • 如果功能过于复杂就拆分开,每个部分保持独立

  • O – OpenClosed Principle 开放/封闭原则

    • 对扩展开放,对修改封闭

    • 增加需求时,扩展新代码,而非修改已有代码

  • L – Liskov Substitution Principle 里氏替换原则

    • 子类能覆盖父类

    • 父类能出现的地方子类就能出现

  • I – Interface Segregation Principle 接口隔离原则

    • 保持接口的单一独立

    • 类似单一职责原则,这里更关注接口

  • D – Dependency Inversion Principle 依赖倒转原则

    • 面向接口编程,依赖于抽象而不依赖于具体

    • 使用方只关注接口而不关注具体类的实现

SO体现较多,举个例子:(比如Promise)

  • 单一职责原则:每个then中的逻辑只做好一件事

  • 开放封闭原则(对扩展开放,对修改封闭):如果新增需求,扩展then

再举个例子:

//checkType('165226226326','mobile')
//result:false
let checkType=function(str, type) {switch (type) {case 'email':return /^[\w-]+(.[\w-]+)*@[\w-]+(.[\w-]+)+$/.test(str)case 'mobile':return /^1[3|4|5|7|8][0-9]{9}$/.test(str);case 'tel':return /^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(str);default:return true;}
}

有以下两个问题:

  • 如果想添加其他规则就得在函数里面增加 case 。添加一个规则就修改一次!这样违反了开放-封闭原则(对扩展开放,对修改关闭)。而且这样也会导致整个 API 变得臃肿,难维护。

  • 比如A页面需要添加一个金额的校验,B页面需要一个日期的校验,但是金额的校验只在A页面需要,日期的校验只在B页面需要。如果一直添加 case 。就是导致A页面把只在B页面需要的校验规则也添加进去,造成不必要的开销。B页面也同理。

建议的方式是给这个 API 增加一个扩展的接口:

let checkType=(function(){let rules={email(str){return /^[\w-]+(.[\w-]+)*@[\w-]+(.[\w-]+)+$/.test(str);},mobile(str){return /^1[3|4|5|7|8][0-9]{9}$/.test(str);}};//暴露接口return {//校验check(str, type){return rules[type]?rules[type](str):false;},//添加规则addRule(type,fn){rules[type]=fn;}}
})();//调用方式
//使用mobile校验规则
console.log(checkType.check('188170239','mobile'));
//添加金额校验规则
checkType.addRule('money',function (str) {return /^[0-9]+(.[0-9]{2})?$/.test(str)
});
//使用金额校验规则
console.log(checkType.check('18.36','money'));

2. 设计模式分类(23种设计模式)

  • 创建型

    • 单例模式(Singleton Pattern)

    • 原型模式(Prototype Pattern)

    • 工厂模式(Factory Method Pattern)

    • 抽象工厂模式(Abstract Factory Pattern)

    • 建造者模式(Builder Pattern)

  • 结构型

    • 适配器模式(Adapter Pattern)

    • 装饰器模式(Decorator Pattern)

    • 代理模式(Proxy Pattern)

    • 外观模式(Facade Pattern)

    • 桥接模式(Bridge Pattern)

    • 组合模式(Composite Pattern)

    • 享元模式(Flyweight Pattern)

  • 行为型

    • 观察者模式(Observer Pattern)

    • 迭代器模式(Iterator Pattern)

    • 策略模式(Strategy Pattern)

    • 模板方法模式(Template Method Pattern)

    • 责任链模式(Chain of Responsibility)

    • 命令模式(Command)

    • 备忘录模式(Memento)

    • 状态模式(State)

    • 访问者模式(Visitor)

    • 中介者模式(Mediator)

    • 解释器模式(Interpreter)

2.1 工厂方法模式(Factory Method Pattern)

工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式使一个类的实例化延迟到了子类。而子类可以重写接口方法以便创建的时候指定自己的对象类型。

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的时候就应该考虑是否用工厂模式;

  • 需要依赖具体环境创建不同实例,这些实例都有相同的行为,这时候我们可以使用工厂模式,简化实现的过程,同时也可以减少每种对象所需的代码量,有利于消除对象间的耦合,提供更大的灵活性

优点

  • 创建对象的过程可能很复杂,但我们只需要关心创建结果。

  • 构造函数和创建者分离, 符合“开闭原则”

  • 一个调用者想创建一个对象,只要知道其名称就可以了。

  • 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。

缺点

  • 添加新产品时,需要编写新的具体产品类,一定程度上增加了系统的复杂度

  • 考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度

什么时候不用

当被应用到错误的问题类型上时,这一模式会给应用程序引入大量不必要的复杂性.除非为创建对象提供一个接口是我们编写的库或者框架的一个设计上目标,否则我会建议使用明确的构造器,以避免不必要的开销。

由于对象的创建过程被高效的抽象在一个接口后面的事实,这也会给依赖于这个过程可能会有多复杂的单元测试带来问题。

例子

  • 曾经我们熟悉的JQuery的$()就是一个工厂函数,它根据传入参数的不同创建元素或者去寻找上下文中的元素,创建成相应的jQuery对象

class jQuery {constructor(selector) {super(selector)}add() {}// 此处省略若干API
}window.$ = function(selector) {return new jQuery(selector)
}
  • vue 的异步组件

在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。例如:

Vue.component('async-example', function (resolve, reject) {setTimeout(function () {// 向 `resolve` 回调传递组件定义resolve({template: '<div>I am async!</div>'})}, 1000)
})

2.2 单例模式(Singleton Pattern)

一个类只有一个实例,并提供一个访问它的全局访问点。

class LoginForm {constructor() {this.state = 'hide'}show() {if (this.state === 'show') {alert('已经显示')return}this.state = 'show'console.log('登录框显示成功')}hide() {if (this.state === 'hide') {alert('已经隐藏')return}this.state = 'hide'console.log('登录框隐藏成功')}}LoginForm.getInstance = (function () {let instancereturn function () {if (!instance) {instance = new LoginForm()}return instance}})()let obj1 = LoginForm.getInstance()
obj1.show()let obj2 = LoginForm.getInstance()
obj2.hide()console.log(obj1 === obj2)

优点

  • 划分命名空间,减少全局变量

  • 增强模块性,把自己的代码组织在一个全局变量名下,放在单一位置,便于维护

  • 且只会实例化一次。简化了代码的调试和维护

缺点

  • 由于单例模式提供的是一种单点访问,所以它有可能导致模块间的强耦合 从而不利于单元测试。无法单独测试一个调用了来自单例的方法的类,而只能把它与那个单例作为一个单元一起测试。

场景例子

  • 定义命名空间和实现分支型方法

  • 登录框

  • vuex 和 redux中的store

2.3 建造者模式(Builder Pattern)

建造者模式是一种对象创建设计模式,它旨在通过一步步的构建流程来创建复杂对象。其代码示例如下:

// 创建 Product 类
class Sandwich {constructor() {this.ingredients = [];}addIngredient(ingredient) {this.ingredients.push(ingredient);}toString() {return this.ingredients.join(', ');}
}// 创建一个建造者类
class SandwichBuilder {constructor() {this.sandwich = new Sandwich();}reset() {this.sandwich = new Sandwich();}putMeat(meat) {this.sandwich.addIngredient(meat);}putCheese(cheese) {this.sandwich.addIngredient(cheese);}putVegetables(vegetables) {this.sandwich.addIngredient(vegetables);}get result() {return this.sandwich;}
}// 创建用户(director)使用的 builder
class SandwichMaker {constructor() {this.builder = new SandwichBuilder();}createCheeseSteakSandwich() {this.builder.reset();this.builder.putMeat('ribeye steak');this.builder.putCheese('american cheese');this.builder.putVegetables(['peppers', 'onions']);return this.builder.result;}
}// 建造一个三明治
const sandwichMaker = new SandwichMaker();
const sandwich = sandwichMaker.createCheeseSteakSandwich();
console.log(`Your sandwich: ${sandwich}`); // Output: Your sandwich: ribeye steak, american cheese, peppers, onions

2.4 抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式提供了一种封装一组具有相同主题的单个工厂的方式。它有一个接口,用于创建相关或依赖对象的家族,而不需要指定实际实现的类。其代码示例如下:

// 创建一组主题对象类型的抽象类
class AnimalFood {provide() {throw new Error('This method must be implemented.');}
}class AnimalToy {provide() {throw new Error('This method must be implemented.');}
}// 创建一组具体代表家族的对象
class HighQualityDogFood extends AnimalFood {provide() {return 'High quality dog food';}
}class HighQualityDogToy extends AnimalToy {provide() {return 'High quality dog toy';}
}class CheapCatFood extends AnimalFood {provide() {return 'Cheap cat food';}
}class CheapCatToy extends AnimalToy {provide() {return 'Cheap cat toy';}
}// 创建一个抽象工厂
class AnimalProductsAbstractFactory {createFood() {throw new Error('This method must be implemented.');}createToy() {throw new Error('This method must be implemented.');}
}// 创建具体工厂类
class HighQualityAnimalProductsFactory extends AnimalProductsAbstractFactory {createFood() {return new HighQualityDogFood();}createToy() {return new HighQualityDogToy();}
}class CheapAnimalProductsFactory extends AnimalProductsAbstractFactory {createFood() {return new CheapCatFood();}createToy() {return new CheapCatToy();}
}// 使用具体工厂类来创建相关的对象
const highQualityAnimalProductsFactory = new HighQualityAnimalProductsFactory();
console.log(highQualityAnimalProductsFactory.createFood().provide()); // Output: High quality dog food
console.log(highQualityAnimalProductsFactory.createToy().provide()); // Output: High quality dog toyconst cheapAnimalProductsFactory = new CheapAnimalProductsFactory();
console.log(cheapAnimalProductsFactory.createFood().provide()); // Output: Cheap cat food
console.log(cheapAnimalProductsFactory.createToy().provide()); // Output: Cheap cat toy

2.5 适配器模式(Adapter Pattern)

将一个类的接口转化为另外一个接口,以满足用户需求,使类之间接口不兼容问题通过适配器得以解决。

class Plug {getName() {return 'iphone充电头';}
}class Target {constructor() {this.plug = new Plug();}getName() {return this.plug.getName() + ' 适配器Type-c充电头';}
}let target = new Target();
target.getName(); // iphone充电头 适配器转Type-c充电头

优点

  • 可以让任何两个没有关联的类一起运行。

  • 提高了类的复用。

  • 适配对象,适配库,适配数据

缺点

  • 额外对象的创建,非直接调用,存在一定的开销(且不像代理模式在某些功能点上可实现性能优化)

  • 如果没必要使用适配器模式的话,可以考虑重构,如果使用的话,尽量把文档完善

场景

  • 整合第三方SDK

  • 封装旧接口

// 自己封装的ajax, 使用方式如下
ajax({url: '/getData',type: 'Post',dataType: 'json',data: {test: 111}
}).done(function() {})
// 因为历史原因,代码中全都是:
// $.ajax({....})// 做一层适配器
var $ = {ajax: function (options) {return ajax(options)}
}
  • vue的computed

<template><div id="example"><p>Original message: "{{ message }}"</p>  <!-- Hello --><p>Computed reversed message: "{{ reversedMessage }}"</p>  <!-- olleH --></div>
</template>
<script type='text/javascript'>export default {name: 'demo',data() {return {message: 'Hello'}},computed: {reversedMessage: function() {return this.message.split('').reverse().join('')}}}
</script>

原有data 中的数据不满足当前的要求,通过计算属性的规则来适配成我们需要的格式,对原有数据并没有改变,只改变了原有数据的表现形式。

不同点

适配器与代理模式相似

  • 适配器模式: 提供一个不同的接口(如不同版本的插头)

  • 代理模式: 提供一模一样的接口


2.6 装饰器模式(Decorator Pattern)

  • 动态地给某个对象添加一些额外的职责,,是一种实现继承的替代方案

  • 在不改变原对象的基础上,通过对其进行包装扩展,使原有对象可以满足用户的更复杂需求,而不会影响从这个类中派生的其他对象

class Cellphone {create() {console.log('生成一个手机')}
}
class Decorator {constructor(cellphone) {this.cellphone = cellphone}create() {this.cellphone.create()this.createShell(cellphone)}createShell() {console.log('生成手机壳')}
}
// 测试代码
let cellphone = new Cellphone()
cellphone.create()console.log('------------')
let dec = new Decorator(cellphone)
dec.create()

场景例子

  • 比如现在有4 种型号的自行车,我们为每种自行车都定义了一个单 独的类。现在要给每种自行车都装上前灯、尾 灯和铃铛这3 种配件。如果使用继承的方式来给 每种自行车创建子类,则需要 4×3 = 12 个子类。 但是如果把前灯、尾灯、铃铛这些对象动态组 合到自行车上面,则只需要额外增加3 个类

  • ES7 Decorator

  • core-decorators

优点

  • 装饰类和被装饰类都只关心自身的核心业务,实现了解耦。

  • 方便动态的扩展功能,且提供了比继承更多的灵活性。

缺点

  • 多层装饰比较复杂。

  • 常常会引入许多小对象,看起来比较相似,实际功能大相径庭,从而使得我们的应用程序架构变得复杂起来


2.7 代理模式(Proxy Pattern)

是为一个对象提供一个代用品或占位符,以便控制对它的访问

假设当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>
  • ES6 的 proxy

  • jQuery.proxy()方法

优点

  • 代理模式能将代理对象与被调用对象分离,降低了系统的耦合度。代理模式在客户端和目标对象之间起到一个中介作用,这样可以起到保护目标对象的作用

  • 代理对象可以扩展目标对象的功能;通过修改代理对象就可以了,符合开闭原则;

缺点

处理请求速度可能有差别,非直接访问存在开销

不同点

装饰者模式实现上和代理模式类似

  • 装饰者模式: 扩展功能,原有功能不变且可直接使用

  • 代理模式: 显示原有功能,但是经过限制之后的


2.8 外观模式(Facade Pattern)

为子系统的一组接口提供一个一致的界面,定义了一个高层接口,这个接口使子系统更加容易使用

1. 兼容浏览器事件绑定

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}
}; 

2. 封装接口

let myEvent = {// ...stop: e => {e.stopPropagation();e.preventDefault();}
};

场景

  • 设计初期,应该要有意识地将不同的两个层分离,比如经典的三层结构,在数据访问层和业务逻辑层、业务逻辑层和表示层之间建立外观Facade

  • 在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂,增加外观Facade可以提供一个简单的接口,减少他们之间的依赖。

  • 在维护一个遗留的大型系统时,可能这个系统已经很难维护了,这时候使用外观Facade也是非常合适的,为系系统开发一个外观Facade类,为设计粗糙和高度复杂的遗留代码提供比较清晰的接口,让新系统和Facade对象交互,Facade与遗留代码交互所有的复杂工作。

参考: 大话设计模式

优点

  • 减少系统相互依赖。

  • 提高灵活性。

  • 提高了安全性

缺点

  • 不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。


2.9 观察者模式(Observer Pattern)

定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使它们能够自动更新自己,当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象需要改变的时候,就应该考虑使用观察者模式。

  • 发布 & 订阅

  • 一对多

// 主题 保存状态,状态变化之后触发所有观察者对象
class Subject {constructor() {this.state = 0this.observers = []}getState() {return this.state}setState(state) {this.state = statethis.notifyAllObservers()}notifyAllObservers() {this.observers.forEach(observer => {observer.update()})}attach(observer) {this.observers.push(observer)}
}// 观察者
class Observer {constructor(name, subject) {this.name = namethis.subject = subjectthis.subject.attach(this)}update() {console.log(`${this.name} update, state: ${this.subject.getState()}`)}
}// 测试
let s = new Subject()
let o1 = new Observer('o1', s)
let o2 = new Observer('02', s)s.setState(12)

场景

  • DOM事件

document.body.addEventListener('click', function() {console.log('hello world!');
});
document.body.click()
  • vue 响应式

优点

  • 支持简单的广播通信,自动通知所有已经订阅过的对象

  • 目标对象与观察者之间的抽象耦合关系能单独扩展以及重用

  • 增加了灵活性

  • 观察者模式所做的工作就是在解耦,让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响到另一边的变化。

缺点

过度使用会导致对象与对象之间的联系弱化,会导致程序难以跟踪维护和理解


2.10 状态模式(State)

允许一个对象在其内部状态改变的时候改变它的行为,对象看起来似乎修改了它的类

// 状态 (弱光、强光、关灯)
class State {constructor(state) {this.state = state}handle(context) {console.log(`this is ${this.state} light`)context.setState(this)}
}
class Context {constructor() {this.state = null}getState() {return this.state}setState(state) {this.state = state}
}
// test 
let context = new Context()
let weak = new State('weak')
let strong = new State('strong')
let off = new State('off')// 弱光
weak.handle(context)
console.log(context.getState())// 强光
strong.handle(context)
console.log(context.getState())// 关闭
off.handle(context)
console.log(context.getState())

场景

  • 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为

  • 一个操作中含有大量的分支语句,而且这些分支语句依赖于该对象的状态

优点

  • 定义了状态与行为之间的关系,封装在一个类里,更直观清晰,增改方便

  • 状态与状态间,行为与行为间彼此独立互不干扰

  • 用对象代替字符串来记录当前状态,使得状态的切换更加一目了然

缺点

  • 会在系统中定义许多状态类

  • 逻辑分散


2.11 迭代器模式(Iterator Pattern)

提供一种方法顺序一个聚合对象中各个元素,而又不暴露该对象的内部表示。

class Iterator {constructor(conatiner) {this.list = conatiner.listthis.index = 0}next() {if (this.hasNext()) {return this.list[this.index++]}return null}hasNext() {if (this.index >= this.list.length) {return false}return true}
}class Container {constructor(list) {this.list = list}getIterator() {return new Iterator(this)}
}// 测试代码
let container = new Container([1, 2, 3, 4, 5])
let iterator = container.getIterator()
while(iterator.hasNext()) {console.log(iterator.next())
}

场景例子

  • Array.prototype.forEach

  • jQuery中的$.each()

  • ES6 Iterator

特点

  • 访问一个聚合对象的内容而无需暴露它的内部表示。

  • 为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作

总结

对于集合内部结果常常变化各异,不想暴露其内部结构的话,但又想让客户代码透明的访问其中的元素,可以使用迭代器模式


2.12 桥接模式(Bridge Pattern)

桥接模式(Bridge)将抽象部分与它的实现部分分离,使它们都可以独立地变化。

class Color {constructor(name){this.name = name}
}
class Shape {constructor(name,color){this.name = namethis.color = color }draw(){console.log(`${this.color.name} ${this.name}`)}
}//测试
let red = new Color('red')
let yellow = new Color('yellow')
let circle = new Shape('circle', red)
circle.draw()
let triangle = new Shape('triangle', yellow)
triangle.draw()

优点

  • 有助于独立地管理各组成部分, 把抽象化与实现化解耦

  • 提高可扩充性

缺点

  • 大量的类将导致开发成本的增加,同时在性能方面可能也会有所减少。

 团队介绍

三翼鸟数字化技术平台-ToC服务平台」以用户行为数据为基础,利用推荐引擎为用户提供“千人千面”的个性化推荐服务,改善用户体验,持续提升核心业务指标。通过构建高效、智能的线上运营系统,全面整合数据资产,实现数据分析-人群圈选-用户触达-后效分析-策略优化的运营闭环,并提供可视化报表,一站式操作提升数字化运营效率。
 

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

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

相关文章

LINUX613计划测put

FTP put ┌────────────────────────────────────────────────────────────────────┐│ • MobaXterm 20.0 • ││ (SSH client, X-serv…

NB-IoT-下行同步、广播信道和信号

这一篇主要讲解以下NPSS/NSSS/NPBCH信号的具体细节。还是依然先分析时频资源&#xff0c;再分析具体信号细节。 1、NPSS信道和信号 NPSS信号总是在每个无线帧的子帧5上。使用符号为3~13个OFDM符号&#xff0c;子载波使用0~10号&#xff08;11个子载波&#xff09;。如果部署为…

Java TCP网络编程核心指南

Java网络编程中TCP通信详解 TCP (Transmission Control Protocol) 是互联网中最核心的传输层协议&#xff0c;提供可靠的、面向连接的字节流传输服务。在Java网络编程中&#xff0c;TCP通信主要通过Socket和ServerSocket类实现。 一、TCP核心特性与Java实现 特性描述Java实现…

SVN迁移Git(保留历史提交记录)

第一步&#xff1a;安装git 下载地址&#xff1a;https://gitforwindows.org/ 第二步&#xff1a;先创建一个git创库&#xff0c;&#xff08;创建过程忽略&#xff09; 第三步&#xff1a;本地新建一个空的项目文件夹&#xff0c;用于存放要迁移的项目代码&#xff0c;我这创…

9.IP数据包分片计算

IP数据报分片计算 题目1&#xff1a;主机发送5400字节数据&#xff0c;MTU1400字节&#xff08;IPv4&#xff09;&#xff0c;填写分片后的字段值。 解答&#xff1a; 分片规则&#xff1a; 每片数据长度尽量接近MTU&#xff08;1400B&#xff09;&#xff0c;IP首部20B&…

pmset - 控制 macOS 系统电源、睡眠、唤醒与节能

文章目录 NAME概要描述SETTINGSETTINGSGETTING安全睡眠参数待机参数UPS 专用参数计划事件参数电源参数说明其他参数示例另请参阅文件 NAME pmset – manipulate power management settings概要 pmset [-a | -b | -c | -u] [setting value] [...]pmset -u [haltlevel percent]…

网络安全防护:点击劫持

目录 1、概念 2、攻击原理&#xff1a;视觉欺骗与层叠控制 3、点击劫持的危害 4、防御点击劫持 4.1 X-Frame-Options HTTP 响应头 (最直接有效) 4.2 Content-Security-Policy (CSP) HTTP 响应头 (现代、更强大) 4.3 客户端 JavaScript 防御 (Frame Busting) 1、概念 点…

Spring Boot常用依赖大全:从入门到精通

springboot <!-- Spring Boot 的 Spring Web MVC 集成 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 注解校验代替ifelse --> <de…

Linux系统下安装elasticsearch6.8并配置ik分词

准备安装包和环境 jdk 由于es是基于java开发的所以需要安装jdk。如果没有安装的话 jdk8下载 下载后配置环境变量安装。 es es6.8下载地址 elasticsearch-6.8.14.tar.gz ik分词器 es分词器需要下载对应es版本的 elasticsearch-analysis-ik-6.8.14.zip 安装es es不推荐使…

OceanBase (DBA)一面面经

1. Oracle高可用和ob高可用&#xff0c;和他们的实现方式&#xff1f; 2.ob的三副本了解吗&#xff0c;ob的三副本怎么保障强一致的&#xff1f; 3.三副本能实现强一致吗&#xff1f; 4.了解ob的数据协调协议吗&#xff1f;说说原理 5.聊聊Oracle&#xff0c;讲一些SQL调优…

PyTorch框架详解(1)

目录 代码会放在每条解释的后面 一.概念&#xff1a; 2.张量的概念&#xff1a; 3.张量的创建 4.张量的数据类型及转换 二.tensor和numpy互转 三.张量的运算 四.索引的操作 五.张量形状操作 维度交换&#xff1a; 六.张量拼接操作 代码会放在每条解释的后面 一.概念…

Spring Boot 与 Kafka 的深度集成实践(一)

引言 ** 在当今的软件开发领域&#xff0c;构建高效、可靠的分布式系统是众多开发者追求的目标。Spring Boot 作为 Java 生态系统中极具影响力的框架&#xff0c;极大地简化了企业级应用的开发流程&#xff0c;提升了开发效率和应用的可维护性。它基于 Spring 框架构建&#…

PIN to PIN兼容设计:MT8370与MT8390核心板开发对比与优化建议

X8390 是基于联发科 MT8390 CPU 的一款开发板&#xff0c; MT8390 与 MT8370 是 PIN to PIN 的封装&#xff0c;可以共用一个核心 板。 MT8390 (Genio 700) 是一款高性能的边缘 AI 物联网平台&#xff0c;广泛应用于智能家居、交 互式零售、工业和商业等领域。它采用…

【论文解读】START:自学习的工具使用者模型

1st author: ‪Chengpeng Li‬ - ‪Google 学术搜索‬ paper: [2503.04625] START: Self-taught Reasoner with Tools code: 暂未公布 5. 总结 (结果先行) 大型语言推理模型&#xff08;Large Reasoning Models, LRMs&#xff09;在模拟人类复杂推理方面取得了显著进展&…

【GitOps】Kubernetes安装ArgoCD,使用阿里云MSE云原生网关暴露服务

🌟 ArgoCD是什么? ArgoCD是一款开源的持续交付(CD)工具,专门为Kubernetes环境设计。它采用GitOps理念,将Git仓库作为应用部署的唯一真实来源(SSOT),实现了声明式的应用部署和管理。 简单来说,ArgoCD就像是一位不知疲倦的"仓库管理员",时刻盯着你的Git仓库,…

三维重建 —— 1. 摄像机几何

文章目录 1. 针孔相机1.1. 针孔成像1.2. 光圈对成像的影响 2. 透视投影相机2.1. 透镜成像2.2. 失焦2.3. 径向畸变2.4. 透视投影的性质 3. 世界坐标系到像素坐标系的变换4. 其它相机模型4.1. 弱透视投影摄像机4.2. 正交投影摄像机4.3. 各种摄像机模型的应用场合 课程视频链接&am…

Linux基本指令(包含vim,用户,文件等方面)超详细

文章目录 Linux 基本指令前序Vim编辑器分为两种设计理念模式转化指令解释 Normal模式移动光标&#xff08;motion 核心&#xff09;常用指令 动作(action)常用指令将动作与移动进行组合 查找&#xff08;正则表达式&#xff09;替换&#xff08;substitude&#xff09;文本对象…

如何彻底删除Neo4j中的所有数据:完整指南

如何彻底删除Neo4j中的所有数据&#xff1a;完整指南 Neo4j作为领先的图数据库&#xff0c;在某些场景下我们需要完全清空数据库中的所有数据。本文将介绍多种删除Neo4j数据的有效方法&#xff0c;涵盖不同版本和部署方式的操作步骤。 一、Neo4j数据删除的常见需求场景 开发…

Keil无法下载程序到STM32 Error: Flash Download failed - Target DLL has been cancelled

背景 Keil通过st-link v2连接STM32&#xff0c;下载报错 Error: Flash Download failed - Target DLL has been cancelled 我有多台STM32需要下载程序&#xff0c;会出现这个问题 原因 应该是Keil保存了设备的相关信息&#xff0c;当换了设备之后下载就会出错 解决办法 断…

CIM和建筑风貌管控平台

2025年的雄安新区&#xff0c;中央绿谷的碧波倒映着现代建筑群&#xff0c;中国星网总部大厦的曲面幕墙与古风飞檐相映成趣。这座“未来之城”的每一处建筑肌理&#xff0c;都离不开一项关键技术——城市信息模型&#xff08;CIM&#xff09;与建筑风貌管控平台的支撑。从雄安到…