JS设计模式(全)

设计原则在设计一些设计模式时,一般遵循如下七项基本原则:1 单一职责原则 (Single Responsibility Principle)2 开放-关闭

设计原则

  • 在设计一些设计模式时,一般遵循如下七项基本原则

1. 单一职责原则 (Single Responsibility Principle)
2. 开放-关闭原则 (Open-Closed Principle)
3. 里氏替换原则 (Liskov Substitution Principle)
4. 依赖倒转原则 (Dependence Inversion Principle)
5. 接口隔离原则 (Interface Segregation Principle)
6. 最少知道原则(The Least Knowledge Principle)
7. 组合/聚合复用原则 (Composite/Aggregate Reuse Principle)

单一职责原则:

1. 一个对象或方法只做一件事情。
2. 如果一个方法承担了过多的职责,那么在需求的变迁过程中,需要改写这个方法的可能性就越大。
3. 应该把对象或方法划分成较小的粒度,提高代码可读性,提高系统可维护性。

开放-关闭原则:

1. 对扩展开放:有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
2. 对修改封闭:一旦设计完成,模块的源代码不能被侵犯,任何人不允许修改已有源代码。
3. 开放封闭的核心思想就是对抽象编程,而不对具体编程,因为抽象相对稳定。
4. 让类依赖于固定的抽象,所以对修改就是封闭的;
5. 而通过面向对象的继承和多态机制,可以实现对抽象体的继承,通过覆写其方法来改变固有行为,实现新的扩展方法,所以对于扩展就是开放的。

最少知道原则:

1. 它描述了一种保持代码松耦合的策略,每个单元对其他单元只拥有有限的知识,只了解与当前单元紧密联系的单元;
2. 现代面向对象程序设计语言通常使用 "." 作为访问标识,LoD 可以被简化为 "仅使用一个点(use only one dot)"。
3. 也就是说,代码 a.b.Method() 违反了 LoD,而 a.Method() 则符合 LoD。
打个比方,人可以命令一条狗行走,但是不应该直接指挥狗的腿行走,应该由狗去指挥它的腿行走。

设计模式

  • 设计模式是我们在 解决问题的时候针对特定问题给出的简洁而优化的处理方案
  • 在 JS 设计模式中,最核心的思想:封装变化。
  • 将变与不变分离,确保变化的部分灵活、不变的部分稳定。

单例模式

单例模式限制实例的数量必须是一个,这个唯一的实例被称作单例(singleton)。
单例模式适合应用在一个广泛的系统范围内、在一个集中的地方来处理某些逻辑。
减少了全局变量的使用,从而清除了命名空间污染和命名冲突的风险。
例子:数据库连接池,连接池需要管理很多连接的生命周期,以便在将来需要对数据库发出请求时可以重用连接。

 

什么是单例模式呢?
我们都知道,构造函数可以创造一个对象
我们 new 很多次构造函数就能得到很多的对象
单例模式:
就是使用构造函数实例化的时候,不管实例化多少回,都是同一个对象
也就是一个构造函数一生只能 new 出一个对象
当我们使用构造函数,每一次 new 出来的对象 属性/功能/方法 完全一样 的时候,我们把他设计成单例模式

核心代码

  • 其实就是判断一下,他曾经有没有 new 出来过对象
  • 如果有,就还继续使用之前的那个对象,如果没有,那么就给你 new 一个

 

  • 应用

 

组合模式

  • 组合模式,就是把几个构造函数的启动方式组合再一起
  • 然后用一个 ”遥控器“ 进行统一调用

 

  • 上面几个构造函数的创造的实例化对象的 启动方式 都一致
  • 那么我们就可以把这几个函数以组合模式的情况书写
  • 然后统一启动(准备一个 组合模式 的构造函数)

 

  • 我们就用我们的组合模式构造函数来吧前面的几个功能组合起来

 

构造器模式

  • 构造器是一个当新建对象的内存被分配后,用来初始化该对象的一个特殊函数,在 JavaScript 中几乎所有的东西都是对象。
  • 同时构造器可以使用的参数,以在第一次创建对象时,设置成员属性的方法的值。
  • 对象定义:状态、属性、行为

 

适配器模式

  • 适配器模式可以将一个接口转换到另一种完全不同的接口,它允许接口不同的组件在一起工作。
  • 例子:新研发出的组件和以往接口完全不同,可以通过适配器模式来兼容已有的老代码。

 

观察者模式

  • 观察者模式包含观察目标和观察者两类对象,
  • 一个目标可以有任意数目的与之相依赖的观察者
  • 一旦观察目标的状态发生改变,所有的观察者都将得到通知。

 

  • 观察者模式(Observer),通常也被叫做 发布-订阅模式 或者 消息模式
  • 官方解释:
  • 当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,解决了主体对象与观察者之间功能的耦合,即一个对象状态改变给其他对象通知的问题

addEventListener

  • 这个东西其实就是一个标准的 观察者模式

 

上面这个就是有一个 无形的观察者 再观察着 btn 的一举一动
当这个 btn 被点击的时候,就会执行 对应的函数
我们也可以多绑定几个函数
说白了: 观察者模式就是我们自己实现一个 addEventListener 的功能
只不过 addEventListaner 只有固定的一些事件,而且只能给 dom 元素绑定
而我们自己写的可以随便绑定一个事件名称,自己选择触发时机而已

书写代码

  • 我们要有一个观察者(这里抽象为一个对象 {})
  • 需要有一个属性,存放消息的盒子(把你绑定的所有事件放在里面)
  • 需要一个 on 方法,用于添加事件
  • 需要一个 emit 方法,用于发布事件(触发)
  • 需要一个 off 方法,把已经添加的方法取消

 

  • 把它写成一个构造函数的形式

 

  • 现在,一个观察者的雏形就出来了
  • 接下来完善方法就可以了

 ON(添加事件)

  • 我们的 on 方法需要接受 两个参数
    • 事件类型
    • 事件处理函数

 

 EMIT(发布事件)

  • 也就是让我们已经订阅好的事件执行一下
  • 同样需要接受两个参数
    • 要触发的事件类型
    • 给事件处理函数传递的参数

class Observer {
constructor () {
this.message = {}
}

on (type, fn) {
// 判断消息盒子里面有没有设置事件类型
if (!this.message[type]) {
// 证明消息盒子里面没有这个事件类型
// 那么我们直接添加进去
// 并且让他的值是一个数组,再数组里面放上事件处理函数
this.message[type] = [fn]
} else {
// 证明消息盒子里面有这个事件类型
// 那么我们直接向数组里面追加事件处理函数就行了
this.message[type].push(fn)
}
}

emit (type, ...arg) {
// 判断你之前有没有订阅过这个事件
if (!this.message[type]) return

// 如果有,那么我们就处理一下参数
const event = {
type: type,
arg: arg || {}
}

// 循环执行为当前事件类型订阅的所有事件处理函数
this.message[type].forEach(item => {
item.call(this, event)
})
}

off () {}
}

 

使用

  • 以上就是最基本的 观察者模式
  • 接下来我们就使用一下试试看

const o = new Observer()

// 准备两个事件处理函数
function a(e) {
console.log('hello')
}

function b(e) {
console.log('world')
}

// 订阅事件
o.on('abc', a)
o.on('abc', b)

// 发布事件(触发)
o.emit('abc', '100', '200', '300') // 两个函数都回执行

// 移除事件
o.off('abc', 'b')

// 再次发布事件(触发)
o.emit('abc', '100', '200', '300') // 只执行一个 a 函数了

发布-订阅模式

  • 发布 + 订阅 = 观察者模式 ?
  • 在观察者模式中,观察者是知道Subject的,Subject一直保持对观察者进行记录。
  • 然而,在发布订阅模式中,发布者和订阅者不知道对方的存在,它们只有通过消息代理进行通信。
  • 在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。

模块模式

模块模式是前端最常用的模式,特别适合维护一段独立的代码片段。
模块模式几乎是所有JS流行的插件、框架的基础,比如jQuery、Backbone、Ember等。
可以创建私有(private)、公有(public)属性。
模块模式要利用 IIFE(立即调用函数表达式)和闭包来形成私有作用域。

工厂模式

  • 工厂模式,顾名思义,就是为了创造对象。
  • 工厂模式类似于现实的工厂生产线,可以生产出大量类似的商品。
  • 工厂模式的优点在于:能解决多个相似的问题,减少大量冗余代码。

策略模式

  • 策略模式定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
  • 策略模式可以有效避免很多if条件语句。
  • 策略模式符合开放-封闭原则,使代码更容易理解和扩展。
  • 策略模式中的代码可以复用。

代理模式

  • 为其他对象提供一种代理以控制对这个对象的访问,客户端甚至感知不到代理层的存在。
  • 代理对象可以代替本体对象被实例化,此时本体对象未真正实例化,等到合适时机再实例化。
  • 代理模式可以延迟创建开销很大的本体对象,他会把本体的实例化推迟到有方法被调用时。