单例模式
保证一个类只有一个实例,并提供一个访问它的全局访问点(调用一个类,任何时候返回的都是同一个实例)。
实现方法:使用一个变量来标志当前是否已经为某个类创建过对象,如果创建了,则在下一次获取该类的实例时,直接返回之前创建的对象,否则就创建一个对象。
单体模式的优点是:
- 可以用来划分命名空间,减少全局变量的数量。
 - 使用单体模式可以使代码组织的更为一致,使代码容易阅读和维护。
 - 可以被实例化,且实例化一次。
 
class Singleton{constructor(name){this.name=namethis.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) //trueconsole.log(single1.name) //guanconsole.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 = truereturn target}// 装饰器@isAnimalclass Cat {// ...}console.log(Cat.isAnimal) // true作用于类属性的装饰器:function readonly(target, name, descriptor) {discriptor.writable = falsereturn discriptor}class Cat {@readonlysay() {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)
