单例模式
保证一个类只有一个实例,并提供一个访问它的全局访问点(调用一个类,任何时候返回的都是同一个实例)。
实现方法:使用一个变量来标志当前是否已经为某个类创建过对象,如果创建了,则在下一次获取该类的实例时,直接返回之前创建的对象,否则就创建一个对象。
单体模式的优点是:
- 可以用来划分命名空间,减少全局变量的数量。
- 使用单体模式可以使代码组织的更为一致,使代码容易阅读和维护。
- 可以被实例化,且实例化一次。
class Singleton{
constructor(name){
this.name=name
this.instance = null
}
static getInstance(name){
if(!this.instance){
this.instance = new Singleton(name)
}
return this.instance
}
}
const ins = new Singleton('hhhh')
let single1 = Singleton.getInstance('guan')
let single2 = Singleton.getInstance('qingchao')
console.log(single1 === single2) //true
console.log(single1.name) //guan
console.log(single2.name) //guan
发布订阅模式 vs 观察者模式
从图中可以看出:
- 观察者与目标(被观察者)是直接进行交互的,包括订阅和触发。
- 发布订阅模式是透过一个中间者当调度中心,相关的订阅与发布都由调度中心来进行协调。
两者的优缺点:
- 观察者模式:优点就是一一对应,比较直观明了,占用内存资源容易进行回收。缺点就是两者耦合。
发布订阅模式:优点就是一方面实现了发布者与订阅者之间的解耦,中间者可在两者操作之间进行更细粒度的控制。如:条件过滤发布,权限控制等等。缺点就是整一个中间调度会越来越庞大,需要手动清除里面的发布回调。
发布订阅模式
发布/订阅模式,订阅者把自己想订阅的事件注册到调度中心,当该事件触发时候,发布者发布该事件到调度中心(顺带上下文),由调度中心统一调度订阅者注册到调度中心的处理代码。
发布者
- 事件中心
- 订阅者
发布者->事件中心<=>订阅者,订阅者需要向事件中心订阅指定的事件 -> 发布者向事件中心发布指定事件内容 -> 事件中心通知订阅者 -> 订阅者收到消息(可能是多个订阅者),到此完成了一次订阅发布的流程。
发布者并不直接发布消息给订阅者,通过调度中心将消息发送给订阅者
解耦
Event 可以理解为事件中心,提供了订阅和发布功能。
订阅者在订阅事件的时候,只关注事件本身,而不关心谁会发布这个事件;发布者在发布事件的时候,只关注事件本身,而不关心谁订阅了这个事件。
class Event {
constructor() {
// 所有 eventType 监听器回调函数(数组)
this.listeners = {}
}
/**
* 订阅事件
* @param {String} eventType 事件类型
* @param {Function} listener 订阅后发布动作触发的回调函数,参数为发布的数据
*/
on(eventType, listener) {
if (!this.listeners[eventType]) {
this.listeners[eventType] = []
}
this.listeners[eventType].push(listener)
}
off(type, fn) {
if (!this.listeners[type]) return;
const index = this.listeners.indexOf(fn);
if (index === -1) return;
this.listeners[type].splice(index, 1);
}
/**
* 发布事件
* @param {String} eventType 事件类型
* @param {Any} data 发布的内容
*/
emit(eventType, data) {
const callbacks = this.listeners[eventType]
if (callbacks) {
callbacks.forEach((c) => {
c(data)
})
}
}
}
const event = new Event()
event.on('open', (data) => {
console.log(data)
})
event.emit('open', { open: true })
观察者模式
发布者和观察者耦合,发布者必须有观察者的方法
class Observer {
update() {
console.log("update……");
}
}
class Subject {
constructor() {
this.observers = [];
}
addObserver(obsever) {
this.observers.push(obsever);
}
notify() {
this.observers.forEach((ob) => ob.update());
}
}
// 测试
// 测试
let subject = new Subject();
let ob = new Observer();
//订阅目标
subject.addObserver(ob);
//目标发布消息调用观察者的更新方法了
subject.notify(); //update
装饰器模式
装饰者(decorator)模式能够在不改变对象自身的基础上,在程序运行期间给对像动态的添加职责(方法或属性)。与继承相比,装饰者是一种更轻便灵活的做法。
简单说:可以动态的给某个对象添加额外的职责,而不会影响从这个类中派生的其它对象。
装饰器本质就是编译时执行的函数,装饰器只能用于类和类的方法,不能用于函数
ES7装饰器
function isAnimal(target) {
target.isAnimal = true
return target
}
// 装饰器
@isAnimal
class Cat {
// ...
}
console.log(Cat.isAnimal) // true
作用于类属性的装饰器:
function readonly(target, name, descriptor) {
discriptor.writable = false
return discriptor
}
class Cat {
@readonly
say() {
console.log("meow ~")
}
}
var kitty = new Cat()
kitty.say = function() {
console.log("woof !")
}
kitty.say() // meow ~
代理模式
提供一种代理以控制对这个对象的访问。 代理模式使得代理对象控制具体对象的引用。代理几乎可以是任何对象:文件,资源,内存中的对象,或者是一些难以复制的东西。
let person = {
name: "guanqingchao"
};
const proxy = new Proxy(person, {
get(target, property) {
if (property in target) {
return target[property];
} else {
throw new ReferenceError('Property "' + property + '" does not exist.');
}
}
});
console.log(proxy.name);
// console.log(proxy.age)