javascript设计模式笔记

 

观察者模式

观察者模型是非常普遍的一种设计模式,通常会用来在不同系统之间进行解耦

观察者模式:两种关键对象和三种关键操作

  1. subject对象:提供三种基本操作方式:被订阅(注册监听方法 register),被取消订阅(移除监听方法 remove),触发事件(notify)

  2. observers对象:业务逻辑执行对象,监听subject对象的调用

/*
* @Author: qiao
* @Date: 2019-06-29 11:01:53
* @Last Modified by: qiao
* @Last Modified time: 2019-07-07 20:52:58
* @Description: 练习二 完善发布订阅者模型
*/
 
/**
* 观察者模式:两种关键对象和三种关键操作
* 1)subject对象:提供三种基本操作方式:被订阅(注册监听方法 register),被取消订阅(移除监听方法 remove),触发事件(notify)
* 2)observers对象:业务逻辑执行对象,监听subject对象的调用
*
* 观察者模型是非常普遍的一种设计模式,通常会用来在不同系统之间进行解耦,大家谈谈在哪些地方见过发布订阅者模型
* 谈论下这种设计模式通常用来解决什么问题
*/
 
function Subject() {
 this.observerList = [];
}
Subject.prototype.register = function(observer) {
 if (!observer || !observer.handler) {
   return;
}
 this.observerList.push(observer);
}
Subject.prototype.remove = function(observer) {
 var index = this.observerList.indexOf(observer);
 this.observerList.splice(index, 1);
}
Subject.prototype.notify = function() {
 var args = Array.prototype.slice.call(arguments);
 this.observerList.forEach(observer => {
   observer.handler && observer.handler.apply(observer, args)
});
}
 
function Observer(handlerfn) {
 this.handler = handlerfn;
}
 
// 测试用例
var ob1 = new Observer(function() {
 var args = Array.prototype.slice.call(arguments);
 console.log('ob1 handler:', args.join(' '));
});
var ob2 = new Observer(function() {
 var args = Array.prototype.slice.call(arguments);
 console.log('ob2 handler:', args.join(' '));
});
var subject = new Subject();
 
subject.register(ob1);
subject.register(ob2);
 
subject.notify('hello', 'world');
 
subject.remove(ob1);
subject.notify('hello', 'world');
 

发布订阅者模式

发布订阅者模式:观察者模式的变种,实现一套自定义事件系统,observers可以订阅不同的事件,subject对象也可以通过触发不同的事件来调用不同的observers

扫描二维码关注公众号,回复: 8115379 查看本文章

/**
* 发布订阅者模式:观察者模式的变种,实现一套自定义事件系统,observers可以订阅不同的事件,subject对象也可以通过触发不同的事件来调用不同的observers
*/
function Subject() {
 this.eventSet = {};
}
Subject.prototype.subscribe = function(event, observer) {
 if (!observer || !observer.handler) {
   return;
}
 if (!this.eventSet[event]) {
   this.eventSet[event] = [];
}
 this.eventSet[event].push(observer);
}
Subject.prototype.remove = function(event, observer) {
 if (!event || !this.eventSet[event]) {
   return;
}
 if (!observer) {
   this.eventSet[event] = [];
   delete this.eventSet[event];
} else {
   var observers = this.eventSet[event];
   var index = observers.indexOf(observer);
   observers.splice(index, 1);
}
}
Subject.prototype.notify = function(event) {
 if (!event || !this.eventSet[event]) {
   return;
}
 var args = Array.prototype.slice.call(arguments, 1);
 var observers = this.eventSet[event];
 observers.forEach(observer => {
   observer.handler && observer.handler.apply(observer, args);
})
}
 
function Observer(handlerfn) {
 this.handler = handlerfn;
}
 
 
// 测试用例
var ob1 = new Observer(function() {
 var args = Array.prototype.slice.call(arguments);
 console.log('ob1 handler:', args.join(' '));
});
var ob2 = new Observer(function() {
 var args = Array.prototype.slice.call(arguments);
 console.log('ob2 handler:', args.join(' '));
});
 
var sb = new Subject();
sb.subscribe('js', ob1);
sb.subscribe('java', ob2);
 
sb.notify('js', 'hello', 'javascript');
sb.notify('java', 'hello', 'java');
 
sb.remove('js', ob1);
 
sb.notify('js', 'hello', 'javascript');
sb.notify('java', 'hello', 'java');

MVC模式

NOTE: 先演示传统模式demo

GUI程序的常用模式:

 

这样抽象过后,便会发现UI程序面临着两个主要问题:

  • 操作UI和执行业务的代码需要解耦和分开处理,以便提升可维护性

  • 如何更新数据和更新界面并且维护它们之间的一致性。

/*
* @Author: qiao
* @Date: 2019-06-29 11:40:49
* @Last Modified by: qiao
* @Last Modified time: 2019-07-03 18:49:03
* @Description: 传统模式
*/

// 传统模式

var inputBtn = document.getElementById('input-btn');
var clearBtn = document.getElementById('clear-btn');
var jsBtn = document.getElementById('js-btn');
// var readBtn = document.getElementById('read-btn');
var valueEle = document.getElementById('value');

// 应用数据
var value;

// 模拟请求
function mockRequest(value) {
 return new Promise(resolve => {
   setTimeout(() => {
     console.log('后台收到数据并响应:', value);
     resolve();
  }, 1000);
});
}

function clearValue() {
 mockRequest('').then(() => { // 模拟业务操作,提交请求
   value = ''; // 数据操作
   valueEle.innerText = ''; // 界面操纵
});
}

function setValue() {
 var input = prompt('请输入值');
 mockRequest(input).then(() => { // 模拟业务操作,提交请求
   value = input; // 数据操作
   valueEle.innerText = value; // 界面操作
});
}

function setJs() {
 var input = 'javascript';
 mockRequest(input).then(() => { // 模拟业务操作,提交请求
   value = input; // 数据操作
   valueEle.innerText = value; // 界面操作
});
}
// function readValue() {
//   alert(value);
// }

clearBtn.addEventListener('click', clearValue);

inputBtn.addEventListener('click', setValue);

jsBtn.addEventListener('click', setJs);

// readBtn.addEventListener('click', readValue);

为了解决上述的问题,在20世纪70年代Smalltalk-80实现了MVC设计模式。Smalltalk-80实现的MVC模式有四个要点:

  • model代表着数据,并且独立于UI,当model变化时,会通知它的观察者们。

  • view显示着当前model的状态。通过观察者模式,view(充当Observer)可以知道model(充当Subject)的修改并且更新自己

  • controller负责响应UI事件处理业务,并且修改model内的数据进而决定view如何更新


 function createModel() {
   var data = {};
   var events = {};
   return {
     register: function(event, handler) {
       var handlers;
       if (handlers = events[event]) {
         handlers.push(handler);
      } else {
         events[event] = [ handler ];
      }
    },
     setData: function(key, value) {
       data[key] = value;
       this.notify(key, value);
    },
     notify: function(key, value) {
       var handlers = events[key];
       handlers && handlers.forEach(function(handler) {
         handler(value);
      });
    },
  };
}
 
 // 在ctrl内编写业务逻辑
 function createCtrl(model) {
   return {
     setValue: function(value) {
         model.setData('count', value); // 数据操作
    }
  };
}
 
 //view
 function createView(model, ctrl) {
   var addBtn, subBtn, countEle,count;
 
   // 在render内编写界面更新
   var _render = {
     updateValue(value) {
       countEle.innerText = value;
    }
  };
 
   var eventHandler = {
     addHandler: function() {
       ctrl.setValue(++count);
    },
     subHandler: function() {
       ctrl.setValue(--count);
    }
  };
 
   return {
     init: function() {
       addBtn = document.getElementById('add-btn');
       subBtn = document.getElementById('sub-btn');
       countEle = document.getElementById('count');
       count = 0;
 
       addBtn.addEventListener('click', eventHandler.addHandler);
       subBtn.addEventListener('click', eventHandler.subHandler);
 
       // 利用model将业务操作和界面更新解耦
       model.register('count', _render.updateValue);
       model.setData('count',0);
    },
     destroy: function() {
       addBtn.removeEventListener('click', eventHandler.addHandler);
       subBtn.removeEventListener('click', eventHandler.subHandler);
 
       countEle = null;
    },
  };
}
 
 var model = createModel();
 var ctrl = createCtrl(model);
 var view = createView(model, ctrl);
 
 view.init();

猜你喜欢

转载自www.cnblogs.com/chuanzi/p/12005910.html