复杂的软件必须有清晰合理的架构,否则无法开发和维护。为了将业务和视图的实现代码分离,目前比较流行三种前端架构:
MVC ( Model-View-Controller)
MVP (Model-View-Presenter)
MVVM( Model-View-ViewModel)
Model 为模型层,主要管理业务模型的数据和行为;View 为展示层,其职责就是管理用户界面。
三个架构模式目的都是为了解耦 Model 和 View,主要不同点就在于三者实现解耦的方案不同。
一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。
简单来说就是通过controller的控制去操作model层的数据,并且返回给view层展示,当用户出发事件的时候,view层会发送指令到controller层,接着controller去通知model层更新数据,model层更新完数据以后直接显示在view层上,这就是MVC的工作原理。
如下图:
代码实现如下:
<select id="animal">
<option value="chick">chickoption>
<option value="hen">henoption>
<option value="cock">cockoption>
select>
<div><span id="name">span>'s voice is <span id="voice">span>.div>
var M = {
voices : {
chick : 'bi bi',
hen : 'gu gu',
cock : 'wo wo'
},
name : '',
voice : '',
change : function(name){
this.name = name;
this.voice = this.voices[name];
V.update();//调用V
},
get : function(k){
return this[k];
}
};
var V = {
init : function(){
document.querySelector('#animal').οnchange= function(){
C.set(this.value);//调用C
};
},
update : function(){
document.querySelector('#name').textContent = M.get('name');
document.querySelector('#voice').textContent = M.get('voice');
}
};
var C = {
init : function(){
V.init();
},
set : function(name){
M.change(name);//调用M
}
};
C.init();
以上代码很清晰分出M、V和C三个模块,V通过事件通知C控制M的变化,M变化后会调用V进行视图更新,整个流程是单向的。
MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。
各部分之间的通信,都是双向的。;View 与 Model 不发生联系,都通过 Presenter 传递;View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。如下图:
代码实现如下:
<select id="animal">
<option value="chick">chickoption>
<option value="hen">henoption>
<option value="cock">cockoption>
select>
<div><span id="name">span>'voice is <span id="voice">span>.div>
var M = {
voices : {
chick : 'bi bi',
hen : 'gu gu',
cock : 'wo wo'
},
name : '',
voice : '',
change : function(name){
this.name = name;
this.voice = this.voices[name];
},
get : function(k){
return this[k];
}
};
var V = {
init : function(){
document.querySelector('#animal').onchange = function(){
C.set(this.value);//调用C
};
},
update : function(kv){
for(k in kv){
document.querySelector('#'+k).textContent = kv[k];
}
}
};
var P = {
init : function(){
V.init();//调用V
},
set : function(name){
M.change(name);//调用M
V.update({
name : M.get('name'),
voice : M.get('voice')
});//调用V
}
};
P.init();
代码来看跟MVC差不太多,区别主要在于M和V没有直接交互,而是通过P来进行完全控制,所以P也被称为控制狂,任何交互上的事情都由很强的控制欲。
MVVM采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。AngularJS 和 Vue 都采用这种模式,而React采用了单向数据流,属于MVP架构。
要实现数据绑定,通常都采用发布者-订阅者模式进行实现,但这部分工作如果由开发人员自己来写代码实现,其实还是挺复杂的,因此,各大平台都提供了各自的内部实现。比如 Vue 和 AngularJS 自身都实现了数据绑定,Android 目前最主流的方案就是采用 Jetpack,iOS 最常用的方案则是结合 ReactiveCocoa(RAC)实现。
MVP 和 MVVM 都是为了解决界面和数据的分离问题,两者只是采用了不同的实现方案。MVP 之间的交互主要是通过接口实现的,其主要弊端就是需要编写大量接口。而 MVVM 则是通过数据绑定的方式实现交互,虽然其实现需要依赖具体的一些框架工具,但明显大大减少了开发者需要编写的代码量。
代码实现如下:
<div id="content">
<select id="animal" data-bind="change:doChange">
<option value="chick">chickoption>
<option value="hen">henoption>
<option value="cock">cockoption>
select>
<div><span data-bind="name">span>'voice is <span data-bind="voice">span>.div>
div>
var M = {
voices : {
chick : 'bi bi',
hen : 'gu gu',
cock : 'wo wo',
},
name : '',
voice : ''
doChang : function(){
M.name = this.value;
M.voice = this.voices[obj.name];
}
};
var V = {
bindEvent : function(el, evt, func){
el['on'+evt] = M[func]();
},
updateText : function(el, text){
el.textContent = text;
}
};
var VM = {
init : function(rootSelector){
this.observer();
this.compiler(rootSelector);
},
paths : {},
observer : function(){
var _this = this;
for(var k in M){
(function(k){
var name = k, value = M[k];
Object.defineProperty(M, name, {
get : function(){
return value;
},
set : function(v){
value = v;
V.updateText(_this.paths[name], v);
}
});
})(k);
}
},
compiler : function(rootSelector){
var binds = document.querySelector(rootSelector).querySelectorAll('[data-bind]');
for(var i=0, len=binds.length;i-1){//事件指令
var directives = directive.split(':');
var evt = directives[0], func = directives[1];
V.bindEvent(el, evt, func);
}else{//文本指令
this.paths[directive] = el;
V.updateText(el, M[directive]);
}
}
}
};
VM.init('#content');
MVC/MVP/MVVM的原理以及代码实现,文章到这里就差不多结束了。可能文章解析的不够全面,需更全面对架构的进阶。我们可以前往这里获取学习笔记方式,**《Android架构学习》**里面有对(架构的全方位解析+大厂架构实战演练)
从 MVC 架构模式到 MVVM,从分离展示层到展示模型层,经过几十年的发展和演变,MVC 架构模式出现了各种各样的变种,并在不同的平台上有着自己的实现。
MVC/MVP/MVVM都是根据不同的应用需求和应用环境逐步发展而来的,它们都有各自优缺点和适用环境。比如Web开发中因为要跨越网络通讯,如果使用MVP或者MVVM来实现代价是巨大的,因为目前来说网络数据很珍贵的资源。