由MVC衍生的经典思想

497 阅读3分钟

MVC是一个非常经典的设计思想,大概在上世纪七十年代malltalk系统诞生时就有了,经过几十年的发展,MVC衍生出了其他设计思想,比如MVVM,MVP,EventBus等。下面介绍其中几个。

MVC基本思想

MVC,由Model,View,Controller三部分组成, 每块的分工如下,

Model(){
    数据
}

View(){
    视图
}

Controller(){
    数据的操作
}

EventBus 事件总线

当代码里有多个对象,对象之间需要一座信息沟通的桥梁时,如果每一个对象都自己实现自己的通信方法,那未免太低效了,最好的办法是我们可以抽象出一个专门负责事件通信的对象,这个对象就是EventBus,DOM API也发扬了同样的思想,把EventTarget这个对象放在原型链的倒数第二层,比Element,Node都高,为的就是所有的元素、节点都可以通过EventTarget里的方法(比如addEventListener)来通信。

表驱动编程

表示原则:把知识叠入数据以求逻辑质朴而健壮。 ——《UNIX编程艺术》

表驱动编程(Table-Driven Approach)是一种把数据和逻辑解耦的编程思想,目的是增加代码的可读性和逻辑的独立性。

表驱动编程中,数据通常有三种访问方式:

直接访问

以一个月的天数为例,我们要写一串if/else 或者switch/case 来表达逻辑。

if(1 == iMonth) {iDays = 31;}
  else if(2 == iMonth) {iDays = 28;}
  else if(3 == iMonth) {iDays = 31;}
  else if(4 == iMonth) {iDays = 30;}
  else if(5 == iMonth) {iDays = 31;}
  else if(6 == iMonth) {iDays = 30;}
  else if(7 == iMonth) {iDays = 31;}
  else if(8 == iMonth) {iDays = 31;}
  else if(9 == iMonth) {iDays = 30;}
  else if(10 == iMonth) {iDays = 31;}
  else if(11 == iMonth) {iDays = 30;}
  else if(12 == iMonth) {iDays = 31;}

但是我们把数据放在一张表里,就不需要这么冗余的逻辑了,

const month = {
  monthTable: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
  get days(month, year) {
    // (year % 4 === 0) && (year % 100 !== 0 || year % 400 === 0) 
    return [month - 1];
  }
}

索引访问

有时通过一次键值转换(对象或者数组),依然无法找到键值。此时可将转换的对应关系写到一个索引表里,即索引访问。而且可以多重索引,或者使用正则匹配。

const c = {
    n: 0,
    events : {
        'click #add': 'add',
        'click #minus': 'minus',
        'click #mul': 'mul',
        'click #div': 'div'
    },
    add(n){ return n+1 },
    minus(n){ return n-1 },
    mul(n){ return n*2 },
    div(n){ return n/2 },
    autoBindEvents() {
        for (let key in c.events){
            const value = c[c.events[key]]
            const spaceIndex = key.indexOf(' ')
            const part1 = key.slice(0, spaceIndex)
            const part2 = key.slice(spaceIndex+1)
            v.el.on(part1, part2, value) // 点击事件
        }
    }
}

阶梯访问

对于一些无规则的数据,例如等级划分。我们没法使用简单的转换将数据转换为索引,但是我们可以使用一个循环,依次检查区间的上下限。

需要注意的细节:

  • 谨慎处理区间端点
  • 可以采用二分/索引加速
const grade = [59,79,84,89,94,100]; 
const level = ["F","E","D","C","B","A"];

const getLevel = g =>{
    for(let i = 0 ; i < grade.length ; i++){
        if(g <= grade[i]) return level[i];
    }
}

参考文章

zhangchen915.com/index.php/a…

efe.baidu.com/blog/mvc-de…