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];
}
}