一、代理模式
- 代理模式,使用者无权访问目标对象,中间加代理,通过代理做授权和控制。
- 对于代理模式的理解,可以举一个例。比如如果广告商想找到明星进行演出,不会直接联系明星,而是联系明星的经纪人,通过经纪人,去与明星之间进行沟通。
- 对于代理模式的应用,在
ES6
中的 Proxy
中也比较常见。 - 代理模式的设计原则验证,代理类和目标类分离,隔离开目标类和使用者,符合开放封闭原则。
- 代理模式与适配器模式的比较:适配器模式是提供一个不同的接口,比如不同版本的插头。代理模式是提供一个一模一样的接口。
- 代理模式与装饰器模式的比较:装饰器模式是扩展功能,原有功能不变且可直接使用。代理模式是显示原有功能,但是经过限制或者阉割之后的。
- 代理模式的代码,如下所示:
let star = {
name: '张XX',
age: 25,
phone: '13910733521'
}
let agent = new Proxy(star, {
get: function (target, key) {
if (key === 'phone') {
return '18611112222'
}
if (key === 'price') {
return 120000
}
return target[key]
},
set: function (target, key, val) {
if (key === 'customPrice') {
if (val < 100000) {
throw new Error('价格太低')
} else {
target[key] = val
return true
}
}
}
})
console.log(agent.name)
console.log(agent.age)
console.log(agent.phone)
console.log(agent.price)
agent.customPrice = 150000
console.log('customPrice', agent.customPrice)
二、外观模式
- 外观模式,为子系统中的一组接口提供了一个高层的接口,使用者使用这个高层接口。
- 对于外观模式的理解,可以举例。比如在去医院看病,接待员去挂号、门诊、划价和取药。
- 外观模式的设计原则验证,不符合单一职责原则和开放封闭原则,因此谨慎使用,不可滥用。
三、观察者模式
- 观察者模式,发布和订阅,一对多。
- 对于观察者模式的理解,可以举例。比如在咖啡馆点好咖啡以后,就可以玩手机、打游戏等,点好之后坐等被叫。
- 对于观察者模式的应用场景,网页事件绑定,
Promise
,jQuery callbacks
和 nodejs
自定义事件等等。在 node.js
中,处理 http
请求,多进程通讯。vue
和 react
组件生命周期触发, vue watch
等。 - 观察者模式的设计原则验证,主题和观察者分离,不是主动触发而是被动监听,两者解耦,符合开放封闭原则。
- 观察者模式的代码,如下所示:
class Subject {
constructor() {
this.state = 0
this.observers = []
}
getState() {
return this.state
}
setState(state) {
this.state = state
this.notifyAllObservers()
}
attach(observer) {
this.observers.push(observer)
}
notifyAllObservers() {
this.observers.forEach(observer => {
observer.update()
})
}
}
class Observer {
constructor(name, subject) {
this.name = name
this.subject = subject
this.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('o2', s)
let o3 = new Observer('o3', s)
s.setState(1)
s.setState(2)
s.setState(3)
四、迭代器模式
- 迭代器模式,顺序访问一个集合,使用者无需知道集合的内部结构和封装。
- 对于迭代器的应用场景,比如
jQuery each
、ES6 Iterator
等等。 ES6 Iterator
的存在原因是 ES6
语法中,有序集合的数据类型已经有很多,需要有一个统一的遍历接口来遍历所有的数据类型。Object
不是有序集合,可以用 Map
代替。ES6 Iterator
具有 [Symbol.iterator]
属性,属性值是函数,执行函数返回一个迭代器。这个迭代器就有 next
方法可顺序迭代子元素,可以运行 Array.prototype[Symbol.iterator]
来测试。ES6 Iterator
与 Generator
的区别是 Iterator
的价值是不限于上述几个类型的遍历,还有 Generator
函数的使用。只要返回的数据符合 Iterator
接口的要求,就可以使用 Iterator
的语法,这就是迭代器模式。- 迭代器模式的设计原则验证,迭代器对象和目标对象分离,迭代器将使用者与目标对象隔离开,符合开放封闭原则。
- 迭代器模式的代码,如下所示:
class Iterator {
constructor(conatiner) {
this.list = conatiner.list
this.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())
}