从命令式到响应式 (二)

知识点回顾,上次主要说了函数式和面向对象,命令式和响应式,push 系统和 pull 系统的差异。在编程范式,风格以外,设计模式也是在程序设计中时时刻刻都在使用的东西,今天主要就讨论一下设计模式这个东西。java

什么是设计模式

模式是一种可复用的解决方案,它有三大好处:程序员

  1. 模式是已经获得验证的解决方案,所以咱们能够在适合的场景中放心的使用它。
  2. 模式很容易被复用,是一种当即可用的解决方案,并且能够对其适当的修改以知足个性化的需求。
  3. 模式富有表达力,它一般有很良好的结构及已经设置好的表达方案的词汇,能够很是轻松的表达出程序员的意图。

其实咱们天天都在接触模式,从最简单的facade(外观模式,jQuery,lodash为表明)到 singleton,再到MVC,模式能够说无处再也不,固然还有rxjs中使用观察者模式等。有模式,就有反模式,既然模式能够带来好处,相应的反模式就会带来坏处,在javaScript中,如下就是咱们常常见到的反模式:angularjs

  1. 在全局上下文中定义大量的变量来污染全局命名空间。这里的全局咱们应该以相对的思惟考虑,而不是特指window对象。例如:在angularjs 中一个controller 做为封闭的做用域,对于它内部定义的各类变量来讲,这个做用域就是全局的,写过angularjs的同窗应该遇到过,在一个controller中定义不少的变量,而后随着功能的增长,愈来愈难以维护。
  2. 修改类的原型,尤为是Object类,比修改更过份的是直接替换。
  3. 之内联的形式使用javaScript。
  4. 给setTimeout 或 setInterval传递字符串而不是函数,这会触发内部 eval 的执行。

响应式中的设计模式

观察者模式

在这种模式中,一个对象维持一系列依赖于它的对象,将有关的状态变动自动的通知给它们。当咱们再也不但愿某个特定的观察者获取注册目标的对象时,它能够从目标的观察者列表中移除。代码以下:编程

观察者列表类,咱们利用这个类来维护观察者的增删改查设计模式

class ObserverList {
    constructor() { };

    list = [];

    add(observer) {
        this.list.push(observer);
    }

    count() {
        return this.list.length;
    }

    get(index) {
        if(index > -1 && index < this.list.length) {
            return this.list[index];
        }else {
            return null;
        }
    }

    indexOf(observer, startIndex) {
        let i = startIndex;

        let pointer = -1;

        while( i< this.list.length) {
            if(this.list[i] === observer) {
                pointer = i;
            }
            i++;
        }

        return pointer;
    }

    removeIndexAt(index) {
        if(index === 0) {
            this.list.shift();
        }else if (index === this.list.length - 1) {
            this.list.pop();
        }
    }
}

主题类,利用这个类来维护一个观察目标,使用观察者列表类来维护其本身的观察者,经过观察者提供的接口向外发送目标上发生的变化。app

class Subject {
    constructor() {
        this.observers = new ObserverList();
    }

    addObserver(observer) {
        this.observers.add(observer);
    }

    removeObserver(observer) {
        this.observers.removeIndexAt(this.observers.indexOf(observer, 0));
    }

    notify(context) {
        const count = this.observers.count();

        for(let i = 0; i< count; i++) {
            this.observers.get(i).update(context);
        }
    }
}

观察者类,为目标发生变化时须要得到通知的对象提供一个更新接口。函数

class Observer {
    constructor() { }

    update() {
      // 获取通知的接口, 不一样的observe 能够针对性的设置更新逻辑
    }
}

而后咱们就能够利用定义好的这些类,实现一些功能,例如,一个主checkbox,当它的状态变化时通知页面上其它的checkbox检查状态,代码大体以下:工具

HTML代码this

<button id="button">Add Observer</button>
<input id="box" type="checkbox">
<div id="container"></div>

javaScript代码spa

const box = document.getElementById('box');
const btn = document.getElementById('button');
const container = document.getElementById('container');

// 工具函数
function extend(source, target) {
    for (let key in source) {
        target[key] = source[key];
    }
}

// 利用工具函数来扩展DOM元素
extend(new Subject(), box);

// 将点击事件通知给观察者
box.onclick = function {
    box.notify(box.checked);
}

btn.onclick = function addNewObserver() {
    const check = document.createElement('input');

    check.type = 'checkbox';

    extend(new Observer(), check);

    // 重写自定义的更新行为
    check.update = (value) => this.checked = value;

    // 为subject的观察者列表中添加新的观察者
    box.addObserver(check);

    // 将观察者附加到容器上
    container.appendChild(check);
}

发布/订阅模式

观察者模式要求但愿接收通知的观察者必须订阅内容改变的事件,而发布/订阅模式中添加了一个事件通道,此通道介于订阅者和发布者之间,这样设置的主要目的是促进发布者和接收者之间的松散耦合,避免订阅者和发布者产和直接的联系,如图:

Observer Pattern

/----<--Subscribe--<--\
    Subject             Observer
      \--->--Fire Event-->--/

Publish/Subscribe Pattern

/----<--Subscribe--<--\
    Publisher-->--publish-->---Event Channel         Subscriber
                                    \--->---fire event-->--/

在实际的应用中, 这两种模式能够结合使用,它们都鼓励开发者思考应用程序之间不一样部分之间的关系,将应用程序分解为更小,更松散耦合的块以提升代码的复用。

这两种模式的优缺点

优势

  1. 只须要维护各个对象之间的通讯接口的一致性,而无需紧密耦合。
  2. 观察者和目标之间能够创建起一种动态的关系,这提供了很大的灵活性,在程序的各部分紧密耦合时,要实现这种动态关系是很是不容易的。

缺点

  1. 在发布/订阅模式中,因为解耦了发布者和订阅者,有时会难以保证程序按照咱们的预期进行。例如,发布者会假设有人在订阅它们,当订阅者发生错误后,因为系统的解耦,发布者并不会看到这一点。
  2. 订阅者之间很是无视彼此的存在,对于变换发布者产生的成本视而不见,因为它们之间动态的关系,难以跟踪依赖更新。

rxjs的实现就是创建在这两种模式的基础之上,预先要了解的基本知识经过这两篇基本上介绍完了,固然都是蜻蜓点水式的,基中任何一个点拿出来均可以长篇大论,各位若有兴趣能够找资料深刻研究。

图片描述

相关文章
相关标签/搜索