全栈工程师修炼指南
熊燚(四火)
Oracle首席软件工程师
立即订阅
2286 人已学习
课程目录
已更新 43 讲 / 共 40 讲
0/4登录后,你可以任选4讲全文学习。
课前必读 (3讲)
开篇词 | 从成长角度看,为什么你应该成为全栈工程师?
免费
学习路径 | 怎样成为一名优秀的全栈工程师?
导读 | 如何学习这个专栏?
第一章 网络协议和 Web 接口 (6讲)
01 | 网络互联的昨天、今天和明天:HTTP 协议的演化
02 | 为HTTP穿上盔甲:HTTPS
03 | 换个角度解决问题:服务端推送技术
04 | 工整与自由的风格之争:SOAP和REST
05 | 权衡的艺术:漫谈Web API的设计
06 | 特别放送:北美大厂如何招聘全栈工程师?
第二章 欢迎来到 MVC 的世界 (7讲)
07 | 解耦是永恒的主题:MVC框架的发展
08 | MVC架构解析:模型(Model)篇
09 | MVC架构解析:视图(View)篇
10 | MVC架构解析:控制器(Controller)篇
11 | 剑走偏锋:面向切面编程
12 | 唯有套路得人心:谈谈Java EE的那些模式
13 | 特别放送:选择比努力更重要
第三章 从后端到前端 (7讲)
14 | 别有洞天:从后端到前端
15 | 重剑无锋,大巧不工:JavaScript面向对象
16 | 百花齐放,百家争鸣:前端MVC框架
17 | 不一样的体验:交互设计和页面布局
18 | 千言万语不及一幅画:谈谈数据可视化
19 | 打开潘多拉盒子:JavaScript异步编程
20 | 特别放送:全栈团队的角色构成
第四章 数据持久化 (7讲)
21 | 赫赫有名的双刃剑:缓存(上)
22 | 赫赫有名的双刃剑:缓存(下)
23 | 知其然,知其所以然:数据的持久化和一致性
24 | 尺有所短,寸有所长:CAP和数据存储技术选择
25 | 设计数据持久层(上):理论分析
26 | 设计数据持久层(下):案例介绍
27 | 特别放送:聊一聊代码审查
第五章 寻找最佳实践 (6讲)
28 | Ops三部曲之一:配置管理
29 | Ops三部曲之二:集群部署
30 | Ops三部曲之三:测试和发布
31 | 防人之心不可无:网站安全问题窥视
32 | 和搜索引擎的对话:SEO的原理和基础
33 | 特别放送:聊一聊程序员学英语
第六章 专题 (7讲)
34 | 网站性能优化(上)
35 | 网站性能优化(下)
36 | 全栈开发中的算法(上)
37 | 全栈开发中的算法(下)
38 | 分页的那些事儿
39 | XML、JSON、YAML比较
40 | 全栈衍化:让全栈意味着更多
全栈工程师修炼指南
登录|注册

08 | MVC架构解析:模型(Model)篇

四火 2019-09-27
你好,我是四火。
在上一讲中,我们了解了 MVC 这个老而弥坚的架构模式,而从这一讲开始,连同第 09、10 讲共计 3 篇,我将分别展开介绍 MVC 三大部分内容。今天我要讲的就是第一部分——模型(Model)。

概念

首先我们要了解的是,我们总在谈“模型”,那到底什么是模型?
简单说来,模型就是当我们使用软件去解决真实世界中各种实际问题的时候,对那些我们关心的实际事物的抽象和简化。比如我们在软件系统中设计“人”这个事物类型的时候,通常只会考虑姓名、性别和年龄等一些系统用得着的必要属性,而不会把性格、血型和生辰八字等我们不关心的东西放进去。
更进一步讲,我们会谈领域模型(Domain Model)。“领域”两个字显然给出了抽象和简化的范围,不同的软件系统所属的领域是不同的,比如金融软件、医疗软件和社交软件等等。如今领域模型的概念包含了比其原本范围定义以外更多的内容,我们会更关注这个领域范围内各个模型实体之间的关系
MVC 中的“模型”,说的是“模型层”,它正是由上述的领域模型来实现的,可是当我们讲这一层的时候,它包含了模型上承载的实实在在的业务数据,还有不同数据间的关联关系。因此,我们在谈模型层的时候,有时候会更关心领域模型这一抽象概念本身,有时候则会更关心数据本身
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《全栈工程师修炼指南》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(18)

  • Luciano李鑫 置顶
    1.大型、复杂项目用贫血模型多一些,小型、简单项目用重写模型多一些。
    2.在命令查询的时候,针对add可以返回自增id。在update的时候返回修改记录数。

    作者回复: 关于 2,你说的返回自增 id 是一种很好的方法,很常用,但是它破坏了 CQRS 对于 Command 的 fire-and-forget 的要求。

    当然,也有一些其它的办法,比如将 id 在客户端生成(这个生成可以是客户端自己生成,也可以是调用服务端的某一个生成 id 的接口生成),但这却又破坏了 REST 接口中 Create 方法不指定 id 的规约。

    再有一个办法,是在客户端生成一个非主键、但被索引的特殊 id,例如 GUID,这样,生成了记录之后,客户端可以使用这个 GUID 去服务端获取这条数据,当然,缺点是需要额外的一列来放置 GUID,且要保证 GUID 的唯一性。

    所以,上面介绍了三种方法,各有利弊,都比较常用。当然,也有一些其它的方法。

    2019-09-29
    3
  • Luciano李鑫
    请问,为什么说在贫血模型中,service增是无状态的,而model增是有状态的,这个“状态”是怎么定义的呢?

    作者回复: 状态,其实就是数据。

    Service 提供了一系列的过程方法,入参进,结果出,但是 Service 并未发生变化。

    Model 则相反,可以创建、修改、删除,这就是状态的变化。

    2019-09-29
    4
  • tt
    赞,这是我订阅的极客时间的课程中为数不多的重度偏向概念与逻辑的课程。

    我本人很少做WEB开发,只是使用过面向对象,这节课一下子就让我领悟了面向对象、面向服务、面向过程、贫血和充血模型。

    程序就是数据结构加算法,业务就是数据加逻辑。从数据和逻辑这两个纬度可以画一个二维四象限图:


               | 数据 | 逻辑
    ------------------------------------------------
    数据 | 承载模型状态,开 | 面向对象
               | 放操作状态的接口 | 充血模型
    ------------------------------------------------
    逻辑 | 面向对象 | 面向服务
               | 充血模型 | 无状态,restful



    虽然很少做WEB开发,但了解过一些内部使用的框架,都有Service和DA,今天知道了,它的名字是贫血模型。

    那从本节课出发,微服务也是把服务拆分,一个目的就是可以快速水平扩展,那应该就大量使用RESTFUL风格。

    但逻辑和数据终归要碰面,ORM就是二者之间的桥梁,对外展示不同的面孔。

    作者回复: 感谢回复。

    关于你提到的“概念与逻辑”,做个说明。

    我是这样认为的,学习全栈技术比较忌讳仅仅学习单个的具体技术,之前的文章和回复中我也多次提到过,毕竟技术种类花样繁多,我们还是需要适当做一些抽象,理解一些通用和共性的东西,既包括一些概念,也包括一些套路(模式)。当然,我们需要通过许多例子来理解它们,这是没错的。

    2019-09-27
    4
  • 零维
    请问老师,如果 CQRS 的命令操作有了返回值会有什么弊端吗?就像举的改进版的示例,如果直接让服务端在 add 操作之后返回 id 会有什么不好的影响吗?

    作者回复: 好问题。我的理解是,返回值就一定程度上意味着解耦可能不够彻底,因为 Command 的理想状况是 fire and forget,所以它才是要求无返回的,存在返回值意味着有一部分逻辑可以拿出去变成 Query。客户端只知道执行成功了,或者执行失败了(有异常抛出)。但是我们在应用到实际系统中的时候,不一定能够做到那么纯粹。

    2019-10-22
    1
  • Mandalorian
    这一课程很棒。如果有可运行的github代码示例,动手试几次,会方便理解很多。

    自己实现不是不行,但肯定实现过程中遇到其它问题,就跑偏了,速度会慢,效率会低。
    2019-09-28
    1
  • 桃源小盼
    非关系型数据库的model层,又该怎么设计呢?
    2019-09-27
    1
  • 疯狂咸鱼
    没想过简单的代码改变蕴含着这么多设计理念和智慧。以前只会死记代码。
    2019-10-21
  • 就叫Hugo也行
    在计算机行业的dargon中,“数据”的同义词是“状态”。“逻辑”的同义词是“服务”、“行为”、“函数”或“功能”。

    作者回复: 👍

    2019-10-12
  • sky
    以前做移动开发的时候,把改变模型状态的方法都放在modal中了,原来这就是充血模型。谢谢老师,课程越来越棒!
    2019-10-04
  • pyhhou
    1. 平时实现业务没有特别涉及到面向对象的概念,都是设计一个个分离的函数,最多是将职责相近的函数放在同一个目录下,不会包装成类,model 层的操作(DB 操作)也都在一个个函数里面完成,这应该算是充血模型?

    2. 看了一下评论以及老师的回复,感觉各种做法都有利弊,思考分析了一下:
      i) 直接返回所需要的 id:这样是方便,但是违反了 CQRS 的原则
      ii) 通过设置全局变量进行交互:如果遇到并行处理的情况会比较麻烦
      iii) 命令下达后再调用查询,通过时间戳来找到最近的一次操作:同样要考虑并行处理,而且如何找到最近的一次时间戳也是一个值得思考的问题
      iv) 交由客户端处理:会产生其他的问题
    总之是要根据具体的场景进行权衡

    作者回复: 关于 1) 这个理解不对。你可以再阅读一下文章,里面有说贫血模型和充血模型是根据什么来区别的。

    2019-10-02
  • CC
    在经历过的项目中使用过 Django 框架,类似于 MVC 架构。不过它的 views 更像是 controllers,Templates 更像是 views。Models 采用的是贫血模型,MVC 之间的交互风格是文中提到的第一种风格。

    关于思考题2,现在工作中使用的方法,正是老师在置顶留言中提到的最后一种,客户端会生成一个 GUID。不过之前没有考虑过前面两种,学习了。
    2019-10-01
  • 易儿易
    看完这讲之后,把上一节给老师提的一个问题自行明白了~
    贫血模型和充血模型区别是Model类是否包含业务逻辑,我之前理解错了,错误的以为是以service层是否包含记录数据的成员变量为区分的(其实这个叫做有无状态)
    那这样理解起来的话,平时的springMVC使用action-service-dao三层的都是贫血模式,我在使用面向对象实现业务时把javabean设置为scope=property并把业务逻辑也写在javabean中、不使用三层结构的模式应该属于充血模式。
    另外有个小疑问:贫血模式下Model层还剩下什么,参数对象?pojo?返回值对象?Model是不是已经名存实亡了?

    作者回复: 无论是贫血模式还是充血模式,Model 层包含的内容都是一致的:逻辑+数据,区别是前者把它们分开、分别容纳在无逻辑的 Model 实体对象和无状态的 Service 中,后者则是统一存放在有状态且有逻辑的 Model 实体对象中。你的疑问是贫血模型下脱离 Service 之后的 Model 实体对象吧,它们只剩下数据,而很少包含,或者不包含逻辑,特别是业务逻辑。

    2019-09-30
    1
  • 每天晒白牙
    MVC架构Model层设计时,有贫血模型和充血模型之分

    贫血模型:把逻辑从模型实体中剥离出去,放到无状态的service层中,达到状态和逻辑的解耦(我经历过的Model层设计一般都是这种贫血模型)

    充血模型:既包涵数据又包涵逻辑,具有完备性和自洽性
    你在设计Model层中一般采用哪种模型?

    设计接口时有一种模式是CQRS(Command Query Responsibility Segregation,命令查询职责分离)
    命令不返回任何结果,但会改变数据的状态,代表写
    查询会返回结果,但不会改变数据状态,就是读
    在设计接口时,写接口参数可以是对象,读接口参数可以是Query对象,设置查询条件
    CQRS这种模式是将读写解耦了

    我现在参与的一个MVC的项目是读写接口没有显性参数,都是从请求中获取参数,对于写操作,会自己组装对象,然后调用DAO层接口,对于读操作,直接给DAO层接口传参查询

    作者回复: 👍

    2019-09-30
  • 编程爱好者
    1.两者都有过,我个人更喜欢贫血模型,职责分明些。
    2.既然不知道,可以让服务器来告诉你。类似于tcp中的syn,ack机制,可以为这次请求增加一个消息编号,然后服务器可以通过这个消息编号告诉方法调用者。
    思考作者为什么这么设计课程,感觉很多内容是架构设计里面涉及的内容-权衡与取舍。

    作者回复: 关于第 2 问,消息编号的想法很好,但是,消息编号是消息编号,而写入数据库对象的 id 是对象的 id,二者并没有必然联系啊。

    2019-09-28
  • 我叫徐小晋
    老师您好:
    第一个问题:基本上都是使用贫血模型
    第二个问题:是不是可以通过查询,然后通过id排序就可以得到最近的数据呢?
    希望老师指正

    作者回复: 第二个问题不对,因为通过 id 排序的方式,在数据量较大的时候不可行;而且,即便能排序,你也不能保证一定能找到那个你刚插入的数据(考虑两条数据并发写入的情况)。这个问题你可以看一下其它人的答复和回复

    2019-09-27
  • 靠人品去赢
    看了这个,我一下理解我们框架提供服务访问的模块为什么命名叫facade。
    2019-09-27
  • anginiit
    最近几个项目都是springMvc,使用贫血模式
    2019-09-27
  • 許敲敲
    前端框架AngularJS遵循的是MVC 模式
    2019-09-27
收起评论
18
返回
顶部