MVVM、MVC框架的認識

推薦博客:
https://blog.csdn.net/jia12216/article/details/55520426

https://www.cnblogs.com/sunny_z/p/7093663.html html


1、MVVM是Model-View-ViewModel的簡寫。它本質上就是MVC 的改進版。MVVM 就是將其中的View 的狀態和行爲抽象化,讓咱們將視圖 UI 和業務邏輯分開。固然這些事 ViewModel 已經幫咱們作了,它能夠取出 Model 的數據同時幫忙處理 View 中因爲須要展現內容而涉及的業務邏輯。微軟的WPF帶來了新的技術體驗,如Silverlight、音頻、視頻、3D、動畫……,這致使了軟件UI層更加細節化、可定製化。同時,在技術層面,WPF也帶來了 諸如BindingDependency Property、Routed Events、Command、DataTemplate、ControlTemplate等新特性。MVVM(Model-View-ViewModel)框架的由來即是MVP(Model-View-Presenter)模式WPF結合的應用方式時發展演變過來的一種新型架構框架。它立足於原有MVP框架而且把WPF的新特性糅合進去,以應對客戶日益複雜的需求變化。
前端

MVVM優勢編輯
MVVM模式和MVC模式同樣,主要目的是分離視圖(View)和模型(Model),有幾大優勢
1. 低耦合。視圖(View)能夠獨立於Model變化和修改,一個ViewModel能夠綁定到不一樣的"View"上,當View變化的時候Model能夠不變,當Model變化的時候View也能夠不變。
2. 可重用性。你能夠把一些視圖邏輯放在一個ViewModel裏面,讓不少view重用這段視圖邏輯。
3. 獨立開發。開發人員能夠專一於業務邏輯和數據的開發(ViewModel),設計人員能夠專一於頁面設計,使用Expression Blending能夠很容易設計界面並生成xaml代碼。
4. 可測試。界面素來是比較難於測試的,而如今測試能夠針對ViewModel來寫。

 

MVVM設計模式的缺點 
第一點:數據綁定使得 Bug 很難被調試。你看到界面異常了,有多是你 View 的代碼有 Bug,也多是 Model 的代碼有問題。數據綁定使得一個位置的 Bug 被快速傳遞到別的位置,要定位原始出問題的地方就變得不那麼容易了。 
第二點:一個大的模塊中,model也會很大,雖然使用方便了也很容易保證了數據的一致性,當時長期持有,不釋放內存,就形成了花費更多的內存。 
第三點:數據雙向綁定不利於代碼重用。客戶端開發最經常使用的重用是View,可是數據雙向綁定技術,讓你在一個View都綁定了一個model,不一樣模塊的model都不一樣。那就不能簡單重用View了。 
 

MVVM框架的主要應用場景vue

  1)針對具備複雜交互邏輯的前端應用
  2)提供基礎的架構抽象
  3)經過Ajax數據持久化,保證前端用戶體驗
  好處就是當先後端進行一些數據交互的時候,前端能夠經過Ajax請求對後端作數據持久化,不須要刷新整個頁面,只須要改動DOM裏須要改動的那部分數據和內容,特別是對於移動端應用場景,刷新頁面的代價太昂貴,會從新加載不少資源,雖然有些資源會被緩存,可是頁面的DOM、JS、CSS都會被瀏覽器從新解析一遍,所以,移動端頁面常常會作成SPA單頁應用,在這個基礎上就誕生了不少MVVM框架,如 Angular、React、Vue

2、MVC(Model View Controller)架構開發,它是蘋果推薦的開發模式,它把頁面分紅三部分:數據模型頁面視圖頁面控制器。一個頁面被分紅多個小視圖,一個頁面共享一個數據模型,只是這個數據模型只被控制器操做,不被各個子視圖處理。這個架構看起來整潔多了,控制器的複雜度下降的不少,頁面的顯示單元被分配到各個視圖去顯示,控制器專一與數據的加工與處理,部分解放了控制器,使它的功能更集中,更緊湊,更小。數據模型,頁面視圖,頁面控制器各個獨立,各司其職。這就是重量級視圖控制的特色。它看起來簡單,更容易理解,全部的邏輯在視圖控制器裏處理。react

一個頁面通常分三個文件夾:頁面文件夾(存放頁面控制器和其子文件夾),頁面文件夾下的model文件夾,頁面文件夾下的view文件夾。想找頁面間的邏輯就去頁面控制器裏找,想看頁面顯示元素就在view文件夾下尋找。你發現數據文件很小,只是數據存儲和轉換,這符合數據單一性原則;視圖部分也很小,只是數據的顯示,徹底不自主;控制器部分仍然擺脫不了過於龐大的弊病。他們就像一我的同樣頭重並且龐大,腳輕,身子小。看到這些你就知道這種開發架構須要進化的方向:強化控制器的重要性,減輕它的體積,把不屬於它的非核心部分遷移到相似視圖的那一部分去,在保證數據的定義性上增長它的功能和做用。angularjs

取消使用單例組裝http請求的作法(單例像類同樣常駐內存,無形中增長類內存的開銷。雖然它作到了統一管理http請求的做用,可是不符合那個頁面的請求那個頁面管理請求的原則)。讓從控制器分化出來的這一部分功能給View,http請求封裝爲一個新操做類。  後端

優勢: 
1. 可定製性 
2. 代碼清晰,便於維護 
3. 測試友好性 
4. 輕量級 
5. 開源 
主要缺點有兩個: 
1. View對Model的依賴,會致使View也包含了業務邏輯; 
2. Controller會變得很厚很複雜。

前端mvc框架,如angularjs,backbone: 設計模式

3、MVP:Model-View-Presenter,MVC的一個演變模式,將Controller換成了Presenter,主要爲了解決上述第一個缺點,將View和Model解耦 


4、瞭解一下Vue雙數據綁定原理數組

vue.js 是採用 數據劫持 結合 發佈者-訂閱者模式 的方式,經過 Object.defineProperty() 來劫持各個屬性的 setter getter ,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調。

具體步驟: 瀏覽器

 

第一步:須要observe的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上 settergetter 緩存

這樣的話,給這個對象的某個值賦值,就會觸發setter,那麼就能監聽到了數據變化

 

第二步:compile解析模板指令,將模板中的變量替換成數據,而後初始化渲染頁面視圖,並將每一個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變更,收到通知,更新視圖

 

第三步:Watcher訂閱者是ObserverCompile之間通訊的橋樑,主要作的事情是:

1、在自身實例化時往屬性訂閱器(dep)裏面添加本身

2、自身必須有一個update()方法

3、待屬性變更dep.notice()通知時,能調用自身的update()方法,並觸發Compile中綁定的回調,則功成身退。

 

第四步:MVVM做爲數據綁定的入口,整合ObserverCompileWatcher三者,經過Observer來監聽本身的model數據變化,經過Compile來解析編譯模板指令,最終利用Watcher搭起ObserverCompile之間的通訊橋樑,達到數據變化 -> 視圖更新;視圖交互變化(input) -> 數據model變動的雙向綁定效果。
 

5、什麼是數據劫持:

  首先咱們應該搞清楚什麼是數據劫持,說白了就是經過Object.defineProperty()來劫持對象屬性的setter和getter操做,在數據變更時作你想要作的事情,舉個栗子:


var data = {
name: 'lhl'
}

Object. keys( data). forEach( function( key){
Object. defineProperty( data, key,{
enumerable: true,
configurable: true,
get : function(){
console. log( 'get');
},
set : function(){
console. log( '監聽到數據發生了變化');
}
})
});
data. name //控制檯會打印出 「get」
data. name = 'hxx' //控制檯會打印出 "監聽到數據發生了變化"
上面的這個栗子能夠看出,咱們徹底能夠控制對象屬性的設置和讀取。在Vue中,做者在不少地方都很是巧妙的運用了defineProperty這個方法,具體用在哪裏而且它又解決了哪些問題,下面作詳細的介紹:
監聽對象屬性的變化
這個應該是Vue很是重要的一塊,其主要思想是observer每一個對象的屬性,添加到訂閱器dep中,當數據發生變化的時候發出notice通知。 相關源代碼以下:(做者採用的是ES6+flow寫的,代碼在src/core/observer/index.js模塊裏面)
export function defineReactive (
obj: Object,
key: string,
val: any,
customSetter?: Function
) {
const dep = new Dep() //建立訂閱對象

const property = Object. getOwnPropertyDescriptor( obj, key)
if ( property && property. configurable === false) {
return
}

// cater for pre-defined getter/setters
const getter = property && property. get
const setter = property && property. set

let childOb = observe( val) //建立一個觀察者對象
Object. defineProperty( obj, key, {
enumerable: true,
configurable: true,
get : function reactiveGetter () {
const value = getter ? getter. call( obj) : val
//這裏也是做者一個巧妙設計,在建立watcher實例的時候,經過調用對象的get方法往訂閱器 dep上添加這個建立的watcher實例
if ( Dep. target) {
dep. depend()
if ( childOb) {
childOb. dep. depend()
}
if ( Array. isArray( value)) {
dependArray( value)
}
}
return value
},
set : function reactiveSetter ( newVal) {
const value = getter ? getter. call( obj) : val
if ( newVal === value) {
return
}
if ( process. env. NODE_ENV !== 'production' && customSetter) {
customSetter()
}
if ( setter) {
setter. call( obj, newVal)
} else {
val = newVal
}
childOb = observe( newVal) //繼續監聽新的屬性值
dep. notify() //這個是真正劫持的目的,要對訂閱者發通知了
}
})
}
以上是監聽對象屬性的變化,那麼下面再看看如何監聽數組的變化:

監聽數組的變化 

const arrayProto = Array. prototype
export const arrayMethods = Object. create( arrayProto)

;[
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
. forEach( function ( method) {
// cache original method
const original = arrayProto[ method]
def( arrayMethods, method, function mutator () {
// avoid leaking arguments:
// http://jsperf.com/closure-with-arguments
let i = arguments. length
const args = new Array( i)
while ( i--) {
args[ i] = arguments[ i]
}
const result = original. apply( this, args)
const ob = this. __ob__
let inserted
switch ( method) {
case 'push':
inserted = args
break
case 'unshift':
inserted = args
break
case 'splice':
inserted = args. slice( 2)
break
}
if ( inserted) ob. observeArray( inserted)
// notify change
ob. dep. notify()
return result
})
})

...
/**
* Define a property.
*/
function def ( obj, key, val, enumerable) {
Object. defineProperty( obj, key, {
value: val,
enumerable: !! enumerable,
writable: true,
configurable: true
});
}
經過上面的代碼能夠看出Vue是經過修改了數組的幾個操做的原型來實現的。

原文自: https://www.cnblogs.com/haohaoday/p/6375149.html

Vue框架很好的利用了Object.defineProperty()這個方法來實現了數據的監聽和修改,同時也達到了很好的模塊間解耦,在平常開發用好這個方法說不定會達到使人意想不到的結果。 

 

發佈訂閱者模式:

 

https://www.sohu.com/a/207062452_464084 

相關文章
相關標籤/搜索