关于MVC模式简单代码实现

经过之前的咬文嚼字说策略在JavaScript中尝试组合模式白话MVC/MVP/MVVM 和 较早之前的进击的观察者模式等文章的铺垫,终于可以把这些理论的东西用于实践了。废话不多说,直奔主题。

GoF 并不将 MVC 引述为一种设计模式,而是把它看做是构建一个用户界面的类的集合。按照他们的观点,它实际上是三种经典设计模式的变异组合:观察者模式,策略模式和组合模式。依赖于框架中的 MVC 如何实现,它也可能会使用工厂和模板模式。GoF Book 提到这些模式在使用 MVC 工作时是非常有用的附加功能。

功能示意:
filter.gif

由一组数据展示三类表格,分别是【stuff,scale】、【stuff,salary】、【stuff,scale,salary】三组视图。另外可以修改指定 stuff 的 scale 或 salary 信息。

stuffs 信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const stuffs = [
{
stuff: 'person_1',
scale: '甲',
salary: '6000'
},
{
stuff: 'person_2',
scale: '乙',
salary: '5000'
},
{
stuff: 'person_3',
scale: '丙',
salary: '9000'
}
];

常规的写法可以这么来:


See the Pen
tableOrdinary
by 夜曉宸 (@yexiaochen)
on CodePen.

职责分配

既然说了 MVC 有那么多好处,我们就用 MVC 的模式来改造下我们的代码。首先我们先划分下职责。
Model 负责对数据的处理并返回目标数据,在这个场景下是筛选 stuff、修改stuff 等职责。
View 负责对目标数据的渲染和处理用户的响应,在这个场景下是各个表格的渲染、change 事件的委托等职责。
Control 负责协调 Model 和 View,在这个场景下是处理委托、处理数据等职责。

此处的 MVC 实现是针对一个 Model 对应多个 View 的代码实现 ,也是为了把观察者模式,策略模式和组合模式模式都用起来。

View

【stuff,scale】、【stuff,salary】、【stuff,scale,salary】三组视图就是三个 View,每个 View 都可以独立渲染自己的一组视图。结合组合模式,我们我们造些视图的叶对象和分支对象。

View

1
2
3
4
5
6
7
8
9
<html>
<head></head>
<body>
<div id="app"></div>
</body>
</html>
<script>
const $APP = document.getElementById('app');
</script>

叶对象(此处有两类视图):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const leafView_1 = () => {
const renderTable = () => {...};
return {
render: renderTable()
};
}

const leafView_2 = (Control) => {
const $ONE = document.getElementById('one');
let $SCALE;
let $SALARY;
const renderSearchTable = params => {...};
const handleModify = e => {...};
const bindEvent = () => {...};
return {
render: () => {...}
};
}

分支对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const branchView = (Control) => {
let $SEARCH, $ALL;
const Views = [];
const addView = () => {...};
const render = () => {...};
const handleSearch = event => {...};
const bindEvent = () => {...}
const initDOM = () => {...};
initDOM();
return {
render,
addView,
};
};

Model

Model 主要是将数据处理成目标数据,并提供 View 注册通知接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const Model = () => {
let stuffData = [];
let filterData = [];
let Views = {};
const ajaxFun = () => [...]; // 模拟后台获取数据;
const setStuffData = () => {};
const filterStuff = () => {};
const setFilterStuff = () => {};
const findStuff = () => {...};
const modifyStuffData = () => {...};
const register = () => {...};
const notify = () => {...};
return {
setStuffData,
setFilterStuff,
modifyStuffData
register,
notify,
};
}

Control

鉴于此处有多类视图,Model 和 View 之间,我们采用了发布订阅模式而不是观察者模式。Model 需要收集 View,然后在数据改变时候更新视图。

1
2
3
4
5
6
7
8
9
10
11
12
13
const Control = () => {
const ModelInstance = Model();
const View_1 = () => {...};
const View_2 = () => {...};
const init = function () {...};
const filter = () => {...};
const modifyStuffInfo = () => {...};
return {
init,
filter,
modifyStuffInfo
};
};

完整的 MVC 代码:


See the Pen
MVC
by 夜曉宸 (@yexiaochen)
on CodePen.

后话

就这么简单的一个需求,改成 MVC 模式后就多了 100 多行代码。就如上篇文章所说一样,如果是简单的需求压根没必要这么折腾。不过,改成 MVC 后,它们各自职责也就更加清晰了,对以后的维护也会好些。

------------- The End -------------
显示评论