• 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

    /**
    * 发布订阅者模式:观察者模式的变种,实现一套自定义事件系统,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();
  • 相关阅读:
    嵌入式框架Zorb Framework搭建三:列表的实现
    嵌入式框架Zorb Framework搭建二:环形缓冲区的实现
    C#比较两个时间大小
    大数据概述
    综合练习:英文词频统计
    熟悉常用的Linux操作
    Python基础画五星红旗
    字符串、组合数据类型练习
    简化版C语言文法
    词法分析实验报告
  • 原文地址:https://www.cnblogs.com/chuanzi/p/12005910.html
Copyright © 2020-2023  润新知