浅析MVC

简介: 浅析MVC

浅析MVC


一、MVC是什么?

MVC(Model View Controller)是一种架构设计模式.

Mmodel,即数据层(数据模型),负责操作所有的数据。

Vview,即视图层,负责所有UI界面,是提供给用户的操作界面,是程序的外壳。

CController,即控制层,负责根据用户从“视图层”输入指令,选取“数据层中的数据”,对其进行相应的操作(绑定事件等),产生最终结果。

这三层是紧密联系在一起的,但又是互相独立的,每一层内部的变化不影响其他层。每一层都对外提供接口(Interface),供上面一层调用。这样一来,软件就可以实现模块化,修改外观或者变更数据都不用修改其他层,大大方便了维护和升级。

关于MVC,事实上没有一个明确的定义,我理解的MVC是将代码结构化的一种抽象的概念,下面给出一些伪代码的示例。

>>Model 数据层(数据模型)

//示例

let Model = {
  data: { 数据源 },
  create: { 增加数据 },
  delete: { 删除数据 },
  update(data) {
    Object.assign(m.data, data); //用新数据替换旧数据
    eventBus.trigger("m:update"); //eventBus触发'm:update'信息,通知View刷新界面
  },
  get: { 获取数据 },
};

>>View 视图层

//示例
let View={
    el:要刷新的元素,
    html:'要显示在页面上的刷新内容'
    init(){
        v.el:初始化需要刷新的元素
    },
    render(){
        刷新页面
    }
}

>>Controller 控制层

let Controller={
    init(){
        v.init()//初始化View
        v.render()//第一次渲染页面
        c.autoBindEvents()//自动的事件绑定
        eventBus.on('m:update',()=>{v.render()}//当enentsBus触发'm:update'是View刷新
    },
    events:{事件以哈希表的方式记录存储},
    //例如:
   events: {
    'click #add1': 'add',
    'click #minus1': 'minus',
    'click #mul2': 'mul',
    'click #divide2': 'div',
    },
    add() {
      m.update({n: m.data.n + 1})
    },
    minus() {
      m.update({n: m.data.n - 1})
    },
    mul() {
      m.update({n: m.data.n * 2})
    },
    div() {
      m.update({n: m.data.n / 2})
    },
    method(){
        data=新数据
        m.update(data) // controller 通知 model去更新数据
    },
    autoBindEvents(){
      for (let key in c.events) { // 遍历events表,然后自动绑定事件
      const value = c[c.events[key]]
      const spaceIndex = key.indexOf(' ')
      const part1 = key.slice(0, spaceIndex) // 拿到 'click'
      const part2 = key.slice(spaceIndex + 1)  // 拿到'#add1'
      v.el.on(part1, part2, value)
    }
}

>> MVC 实例

我们的目标是做一个加减乘除计算器

每次点击加、减、乘、除按钮,数值就会变,基本思想就是监听click事件

import './app1.css'
import $ from 'jquery'
const eventBus = $(window)
// 数据相关都放到m
const m = {
  data: {
    n: parseInt(localStorage.getItem('n'))
  },
  create() {},
  delete() {},
  update(data) {
    Object.assign(m.data, data)
    eventBus.trigger('m:updated')
    localStorage.setItem('n', m.data.n)
  },
  get() {}
}
// 视图相关都放到v
const v = {
  el: null,
  html: `
  <div>
    <div class="output">
      <span id="number">{{n}}</span>
    </div>
    <div class="actions">
      <button id="add1">+1</button>
      <button id="minus1">-1</button>
      <button id="mul2">*2</button>
      <button id="divide2">÷2</button>
    </div>
  </div>
`,
  init(container) {
    v.el = $(container)
  },
  render(n) {
    if (v.el.children.length !== 0) v.el.empty()
    $(v.html.replace('{{n}}', n))
      .appendTo(v.el)
  }
}
// 其他都c
const c = {
  init(container) {
    v.init(container)
    v.render(m.data.n) // view = render(data)
    c.autoBindEvents()
    eventBus.on('m:updated', () => {
      console.log('here')
      v.render(m.data.n)
    })
  },
  events: {
    'click #add1': 'add',
    'click #minus1': 'minus',
    'click #mul2': 'mul',
    'click #divide2': 'div',
  },
  add() {
    m.update({n: m.data.n + 1})
  },
  minus() {
    m.update({n: m.data.n - 1})
  },
  mul() {
    m.update({n: m.data.n * 2})
  },
  div() {
    m.update({n: m.data.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)
    }
  }
}
export default c

在外部引用时就直接

import x from './app1.js'
x.init('#app1') 把容器div传进去
然后在html里写一个<div id="app1"></div>作为容器即可

二、EventBus

>>EventBus是什么?

EventBus主要用于对象之间的通信,比如在上面的例子中,Model 数据模型 和View 视图模型彼此不知道彼此的存在,但是又需要通信,于是就要用到EventBus

总结:使用 eventBus 可以满足最小知识原则,m 和 v 互相不知道对方的细节,但是却可以调用对方的功能

>>EventBus 常用API

eventBus 提供了 on、off 和 trigger 等 API,on 用于监听事件,trigger 用于触发事件

比如在上面的MVC模型中, M数据模型更新时,会 trigger 触发一个事件

EventBus.on()监听事件

EventBus.trigger()触发事件

EventBus.on()取消监听事件

eventBus.trigger('m:updated') //触发事件 
eventBus.on('m:updated',()=>{ //监听事件
     v.render(m.data.n)
 })

三、表驱动程序

随着逻辑复杂性的增加,if/else 或switch中的代码将变得越来越肿,代码可读性不强。所谓的表驱动程序,指的是把一大堆的if...else这样的逻辑处理,转化成从一个hash表中查找key--value对的过程。

例如如果要一个可以返回每个月中天数的函数(为简单起见不考虑闰年),用if else:

function iGetMonthDays(iMonth) {
  let iDays;
  if(iMonth === 1) {iDays = 31;}
  else if(iMonth === 2) {iDays = 28;}
  else if(iMonth === 3) {iDays = 31;}
  else if(iMonth === 4) {iDays = 30;}
  else if(iMonth === 5) {iDays = 31;}
  else if(iMonth === 6) {iDays = 30;}
  else if(iMonth === 7) {iDays = 31;}
  else if(iMonth === 8) {iDays = 31;}
  else if(iMonth === 9) {iDays = 30;}
  else if(iMonth === 10) {iDays = 31;}
  else if(iMonth === 11) {iDays = 30;}
  else if(iMonth === 12) {iDays = 31;}
  return iDays;
}

用表驱动程序(包括闰年判断):

const monthDays = [
  [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
  [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
]
function getMonthDays(month, year) {
  let isLeapYear = (year % 4 === 0) && (year % 100 !== 0 || year % 400 === 0) ? 1 : 0
  return monthDays[isLeapYear][(month - 1)];
}
console.log(getMonthDays(2, 2000))

从上面的代码就可体现出用表驱动程序有以下优点:

  • 减少了大量重复代码
  • 提高了代码的可读性

四、关于模块化

MDN文档:JavaScript modules 模块

>>模块化

这里的模块化值得是前端模块化模块化MVC的重要前提。模块化就是把相对独立的代码从一大段代码里抽取成一个个小模块每个模块之间相对独立,方便日后的维护。

ES6 的语法里引入了 Import 和 export 就是用来实现模块化。

export default c; // 默认导出
export { c }; // 另外一种导出方式。记得要加花括号

>>最小知识原则

以最少的知识使用一个模块,平时我们需要在 html 里引入 css 和 js,现在只需要引入一个模块 js 就够了。

网络异常,图片无法展示
|

>>M+V+C

每个模块都可以用M+V+C的模式搞定,即使MVC在vue 里浓缩成了一个 V。

>>事不过三(抽象思维)

把重复的事情抽象简单

  • 重复的代码==>抽象成函数
  • 同样的属性==>抽象成原型或类
  • 同样的原型==>使用继承
相关文章
|
3天前
|
云安全 人工智能 自然语言处理
AI说的每一句话,都靠谱吗?
阿里云提供AI全栈安全能力,其中针对AI输入与输出环节的安全合规挑战,我们构建了“开箱即用”与“按需增强”相结合的多层次、可配置的内容安全机制。
|
10天前
|
域名解析 人工智能
【实操攻略】手把手教学,免费领取.CN域名
即日起至2025年12月31日,购买万小智AI建站或云·企业官网,每单可免费领1个.CN域名首年!跟我了解领取攻略吧~
|
4天前
|
安全 Java Android开发
深度解析 Android 崩溃捕获原理及从崩溃到归因的闭环实践
崩溃堆栈全是 a.b.c?Native 错误查不到行号?本文详解 Android 崩溃采集全链路原理,教你如何把“天书”变“说明书”。RUM SDK 已支持一键接入。
418 187
|
2天前
|
数据采集 消息中间件 人工智能
跨系统数据搬运的全方位解析,包括定义、痛点、技术、方法及智能体解决方案
跨系统数据搬运打通企业数据孤岛,实现CRM、ERP等系统高效互通。伴随数字化转型,全球市场规模超150亿美元,中国年增速达30%。本文详解其定义、痛点、技术原理、主流方法及智能体新范式,结合实在Agent等案例,揭示从数据割裂到智能流通的实践路径,助力企业降本增效,释放数据价值。
|
8天前
|
人工智能 自然语言处理 安全
国内主流Agent工具功能全维度对比:从技术内核到场景落地,一篇读懂所有选择
2024年全球AI Agent市场规模达52.9亿美元,预计2030年将增长至471亿美元,亚太地区增速领先。国内Agent工具呈现“百花齐放”格局,涵盖政务、金融、电商等多场景。本文深入解析实在智能实在Agent等主流产品,在技术架构、任务规划、多模态交互、工具集成等方面进行全维度对比,结合市场反馈与行业趋势,为企业及个人用户提供科学选型指南,助力高效落地AI智能体应用。
|
4天前
|
消息中间件 安全 NoSQL
阿里云通过中国信通院首批安全可信中间件评估
近日,由中国信通院主办的 2025(第五届)数字化转型发展大会在京举行。会上,“阿里云应用服务器软件 AliEE”、“消息队列软件 RocketMQ”、“云数据库 Tair”三款产品成功通过中国信通院“安全可信中间件”系列评估,成为首批获此认证的中间件产品。此次评估覆盖安全可信要求、功能完备性、安全防护能力、性能表现、可靠性与可维护性等核心指标,标志着阿里云中间件产品在多架构适配与安全能力上达到行业领先水平。
313 194