设计原则

开放封闭原则 OCP 对扩展开放 对修改封闭

工厂模式

简单工厂模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Man {
constructor(name) {
this.name = name
}
alertName() {
alert(this.name)
}
}

class Factory {
public static create(name): Man {
return new Man(name)
}
}

Factory.create('Bobo').alertName()
  • 工厂模式并不仅仅是用来 new 出实例
  • 隐藏创建实例的复杂度,只需提供一个接口,传递对应的参数,就可返回实例;至于这些参数怎么使用,内部有什么逻辑并不关心
  • Vue createComponent 创建异步组件
  • React createElement('div', {}, children) 生成 vnode

单例模式

1
2
3
4
5
6
7
8
9
10
11
12
13
class Singleton {
constructor() {}
}

Singleton.getInstance = (function() {
let instance
return function() {
if (!instance) {
instance = new Singleton()
}
return instance
}
})()
  • 全局缓存
  • 全局状态管理 Vuex
  • 全局 loading dialog
  • 购物车 数据库连接

适配器模式

适配器用来解决两个接口不兼容的情况,不需要改变已有的接口,通过包装一层的方式实现两个接口的正常协作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Plug {
getName() {
return '港版插头'
}
}

class Target {
constructor() {
this.plug = new Plug()
}
getName() {
return this.plug.getName() + ' 适配器转二脚插头'
}
}

let target = new Target()
target.getName() // 港版插头 适配器转二脚插头
  • computed 计算属性 时间戳转日期 这一过程

装饰器模式

不改变已有接口,给对象添加功能

面向切面编程 AOP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
function logDec(target) {
target.flag = true
}

function readonly(target, name, descriptor) {
descriptor.writable = false
return descriptor
}

function log(target, name, descriptor) {
const value = descriptor.value // 暂存 fn 函数
/* 装饰 fn 函数 */
descriptor.value = function(param) {
console.log(`Calling ${name} with `, param) // 打印日志
return value.call(this, param) // 执行原来的 fn 函数
}
return descriptor
}

@logDec
class Test {
@readonly
name = 'Bobo'

@log
public fn(param) {
// ...
}
}

let t = new Test()

console.log(Log.flag) // true

t.name = 'daidaibo' // 不可修改
  • ES7 和 TS 装饰器语法

代理模式

不让外部直接访问到对象

1
2
3
new Proxy

Object.defineProperty
  • 事件代理

观察者模式

1
2
3
btn.addEventListener('click', () => {
// ...
})
  • Subject 和 Observer 直接绑定,中间无媒介
  • addEventListener 事件监听

发布订阅模式

  • Publisher 和 Observer 解藕,中间有媒介
  • EventBus 自定义事件
  • Vue 响应式 依赖收集 派发更新

外观模式

1
2
3
4
5
6
7
8
9
function addEvent(elem, evType, fn, useCapture) {
if (elem.addEventListener) {
elem.addEventListener(evType, fn, useCapture)
} else if (elem.attachEvent) {
elem.attachEvent('on' + evType, fn)
} else {
elem['on' + evType] = fn
}
}

迭代器模式

1
2
3
4
5
6
7
8
9
10
obj[Symbol.iterator] = function () {
return {
next() {
return {
value,
done: true
}
}
}
}

原型链模式