30-10 之Presentation Layer - MVVM ( Model-View-ViewModel )

这个东东主要的概念来自 Martin Fowler 所写的 《 Presentation Model 》这篇文章,MVVM 基本上算是 PM ( Presentation Model ) 的变体,不过当初 PM 主要是以 GUI 为主撰写,不太确定是否与 web 打架…

( 小备注: 这个人的 Blog 可以说是通往软件架构师必看之 Blog )

接下来谈谈 MVVM 的三个主题

  • Model : 基本上就是资料源,API 或是资料库都有可能。
  • ViewModel : 会从 model 抓取 view 所需要的资料,并且维护 state。
  • View : 纯 UI,以 web 来说就是纯 html。

https://ithelp.ithome.com.tw/upload/images/20210925/20089358etPNL6fXG0.png
图片来源: educative-Acing the JavaScript Design Patterns Interview

认真说,我第一眼看到就觉得,viewModel 的功能怎麽和 MVP 的 presenter 有点像呢 ? 这里有几个重点和 MVP 与 MVC 不太一样。

  • view 与 model 本身有 data binding,由 view model 这实作,
  • MVP 的 view 有一些画面逻辑,而 MVVM 的 view 就是纯画面例如 web html。

范例

这里的范例我直接从 educative 内的范例来抓下重点部份来说明。

  • Model : 这里主要有使用 pub/sub 模式,当 model 有什麽变化时,会去通知 observer ( Ex. setNameValue 这里面 ),这里没有用 EventEmitter (nodejs) 主要的原因在於,这个范例是前端用的。
  • ViewModel : 这个范例中,它几乎是实作了 date-binding 也就是将 view 与 model 进行双向绑定,当 model 资料有变动就会去更新 view,反之也是。
  • View : 就是纯 html 了。
// Model
class Model {
  constructor () {
    this.model = { name: 'Mark' }
    this.observers = []
  }

  subscribe (observer) {
    this.observers.push(observer)
  }

  notifyObservers (attrName, newVal) {
    for (let i = 0; i < this.observers.length; i++) {
      this.observers[i](attrName, newVal)
    }
  }

  getCurrentName (nameKey) {
    return this.model[nameKey]
  }

  setNameValue (nameKey, value) {
    this.model[nameKey] = value
    this.notifyObservers(nameKey, value)
  }
}

// ViewModel

class ViewModel {
  constructor (model) {
    this.bind = function (viewElement, modelElement) {
      // 将 view element 与 model element 绑在一起。
      viewElement.value = model.getCurrentName(modelElement)
      // 当 view 有什麽事件时,会执行 model 的事件
      viewElement.addEventListener('input', () => {
        model.setNameValue(viewElement.name, viewElement.value)
      })
      // 当 model 发生变化时,会自动修改 view 的值
      model.subscribe((attrName, newValue) => {
        document.getElementsByName(attrName).forEach((elem) => {
          elem.value = newValue.toUpperCase()
        })
      })
    }
  }
}

// View 纯 HTML
<input type="text" name = "name" id="name">

// 使用时
const nameInput = document.getElementById('name');
const model = new Model()
const viewModel = new ViewModel(model);
viewModel.bind(nameInput, 'name');

小总结

这个知识点可以用来解释什麽现象

我自已的看法 MVVM 有点感觉是给纯前端使用,你可以想成几乎每什麽商业逻辑,单纯的重点就在於 :

『 画面 』与 『 资料 』的 『 绑定 』

有点像是之前听过的 vue 的『 双向绑定 』,这样感觉 vue 应该是以 MVVM 为基础理念来设计,但是上网查了一下,知乎有一篇在讨论这个主题,有兴趣的看一下。不过先说好我是後端,对前端的事情不太熟喔

知乎 - 为什么尤雨溪尤大说VUE没有完全遵循MVVM?

这个知识点可以和以前的什麽知识连结呢 ?

我的脑袋就是迸出了以下几个词 :

  • 双向绑定
  • 单向绑定

这两个东西前端应该是非常的常听到,我这里比较想知道的是,这两个的优缺比较,然後一下我觉得这篇文章还不错,可以参考看看,不过我不是前端,不一定专业。

前端三大框架:资料系结与资料流

我要如何运用这个知识点 ?

我突然想到,以後端的世界来说,很常会将资料存在 cache 与 db 中,这个应该有办法进行『 双向绑定的概念 』这样当资料库更新时,自动也会更新 cache 的资料。

参考资料


<<:  <Day10> Contract — 取得选择权(Options)资讯

>>:  Day 10 - 非同步的 setState()

OK集#29-白话文Excel-公式现形记

话说,我曾经教过大家,如何让整个工作表的公式们现形 但有的时候,在文件交接或说明时,我们不需要把整张...

Day20 浅谈AJAX?

大家好我是乌木白,今天要和大家介绍的是 AJAX,AJAX 是我在学习 JavaScript 这门...

[Golang]同步工具-sync包的Once-心智图总结

1. sync.Once的功用是什麽? A. 只执行ㄧ次函数。 更具体说,需要执行函数的时候,呼叫s...

用一半的时间做两倍的事

听说,这个书名引发了一些争议。老板角色的人看这本书都认为RD团队读完後就是吃了大补丸,以後做专案只需...

[06] [Flask 快速上手笔记] 05. 发送请求与文件上传

在 Flask 里面导入 request 套件包 from flask import request...