08 | MVC架构解析:模型(Model)篇
08 | MVC架构解析:模型(Model)篇
讲述:四火
时长17:07大小15.63M
概念
贫血模型和充血模型
内部层次划分
CQRS 模式
总结思考
扩展阅读
赞 3
提建议
精选留言(20)
- Luciano李鑫置顶2019-09-291.大型、复杂项目用贫血模型多一些,小型、简单项目用重写模型多一些。 2.在命令查询的时候,针对add可以返回自增id。在update的时候返回修改记录数。
作者回复: 关于 2,你说的返回自增 id 是一种很好的方法,很常用,但是它破坏了 CQRS 对于 Command 的 fire-and-forget 的要求。 当然,也有一些其它的办法,比如将 id 在客户端生成(这个生成可以是客户端自己生成,也可以是调用服务端的某一个生成 id 的接口生成),但这却又破坏了 REST 接口中 Create 方法不指定 id 的规约。 再有一个办法,是在客户端生成一个非主键、但被索引的特殊 id,例如 GUID,这样,生成了记录之后,客户端可以使用这个 GUID 去服务端获取这条数据,当然,缺点是需要额外的一列来放置 GUID,且要保证 GUID 的唯一性。 所以,上面介绍了三种方法,各有利弊,都比较常用。当然,也有一些其它的方法。
9 - Luciano李鑫2019-09-29请问,为什么说在贫血模型中,service增是无状态的,而model增是有状态的,这个“状态”是怎么定义的呢?
作者回复: 状态,其实就是数据。 Service 提供了一系列的过程方法,入参进,结果出,但是 Service 并未发生变化。 Model 则相反,可以创建、修改、删除,这就是状态的变化。
8 - tt2019-09-27赞,这是我订阅的极客时间的课程中为数不多的重度偏向概念与逻辑的课程。 我本人很少做WEB开发,只是使用过面向对象,这节课一下子就让我领悟了面向对象、面向服务、面向过程、贫血和充血模型。 程序就是数据结构加算法,业务就是数据加逻辑。从数据和逻辑这两个纬度可以画一个二维四象限图: | 数据 | 逻辑 ------------------------------------------------ 数据 | 承载模型状态,开 | 面向对象 | 放操作状态的接口 | 充血模型 ------------------------------------------------ 逻辑 | 面向对象 | 面向服务 | 充血模型 | 无状态,restful 虽然很少做WEB开发,但了解过一些内部使用的框架,都有Service和DA,今天知道了,它的名字是贫血模型。 那从本节课出发,微服务也是把服务拆分,一个目的就是可以快速水平扩展,那应该就大量使用RESTFUL风格。 但逻辑和数据终归要碰面,ORM就是二者之间的桥梁,对外展示不同的面孔。展开
作者回复: 感谢回复。 关于你提到的“概念与逻辑”,做个说明。 我是这样认为的,学习全栈技术比较忌讳仅仅学习单个的具体技术,之前的文章和回复中我也多次提到过,毕竟技术种类花样繁多,我们还是需要适当做一些抽象,理解一些通用和共性的东西,既包括一些概念,也包括一些套路(模式)。当然,我们需要通过许多例子来理解它们,这是没错的。
5 - 零维2019-10-22请问老师,如果 CQRS 的命令操作有了返回值会有什么弊端吗?就像举的改进版的示例,如果直接让服务端在 add 操作之后返回 id 会有什么不好的影响吗?
作者回复: 好问题。我的理解是,返回值就一定程度上意味着解耦可能不够彻底,因为 Command 的理想状况是 fire and forget,所以它才是要求无返回的,存在返回值意味着有一部分逻辑可以拿出去变成 Query。客户端只知道执行成功了,或者执行失败了(有异常抛出)。但是我们在应用到实际系统中的时候,不一定能够做到那么纯粹。
3 - 就叫Hugo也行2019-10-12在计算机行业的dargon中,“数据”的同义词是“状态”。“逻辑”的同义词是“服务”、“行为”、“函数”或“功能”。
作者回复: 👍
4 - 桃源小盼2019-09-27非关系型数据库的model层,又该怎么设计呢?2
- Geek_89bbab2020-06-11cqrs中发送command服务方还是需要返回一些成功失败应答的吧,不可能啥都不返回吧。 这里有些疑惑:发送一个创建对象的command,然后立刻去查询,发现没有查询到怎么办,可能是内部服务挂掉,也可能是数据同步慢?对于前端怎么显示比较好。
作者回复: 严格的CQRS来说的话,命令要返回执行结果,但是不返回写入成功的完整对象。 我认为,在CQRS的情况下,如果写入操作返回成功,写入后的查询没有查询到,无论可能是数据一致性的问题(bug),还是数据访问竞争的问题(非bug),对于该次查询来说,都属于查询操作无法找到数据的场景,按照它结合业务来设计。
1 - CC2019-10-01在经历过的项目中使用过 Django 框架,类似于 MVC 架构。不过它的 views 更像是 controllers,Templates 更像是 views。Models 采用的是贫血模型,MVC 之间的交互风格是文中提到的第一种风格。 关于思考题2,现在工作中使用的方法,正是老师在置顶留言中提到的最后一种,客户端会生成一个 GUID。不过之前没有考虑过前面两种,学习了。展开共 1 条评论1
- 四喜2019-09-28这一课程很棒。如果有可运行的github代码示例,动手试几次,会方便理解很多。 自己实现不是不行,但肯定实现过程中遇到其它问题,就跑偏了,速度会慢,效率会低。2
- 编程爱好者2019-09-281.两者都有过,我个人更喜欢贫血模型,职责分明些。 2.既然不知道,可以让服务器来告诉你。类似于tcp中的syn,ack机制,可以为这次请求增加一个消息编号,然后服务器可以通过这个消息编号告诉方法调用者。 思考作者为什么这么设计课程,感觉很多内容是架构设计里面涉及的内容-权衡与取舍。
作者回复: 关于第 2 问,消息编号的想法很好,但是,消息编号是消息编号,而写入数据库对象的 id 是对象的 id,二者并没有必然联系啊。
共 2 条评论1 - Johnny2022-06-16感谢老师,让我深刻理解了贫血和充血模式。 一直不理解为什么实际开发中,前辈们写的对象都只有数据,没有逻辑,面向对象的教程看了好多遍,对象应该有属性和方法,导致学习和实际开发有很大脱节。 其实,是分层解耦导致了这种结果。真是醍醐灌顶!
- paperen2020-06-011、贫血与充血都有用,但贫血更多,就是封装到service中实现跟逻辑相关的动作 2、对于CQRS模式add方法想获取新增的bookid,是不是可以对book模型增加一个方法叫getLastAddId来获取最近添加的bookid?但我还是觉得不需要做得那么极尽,可能还没深刻理解,觉得add保留返回bookid对解耦并没关系呢
作者回复: 关于 #2,这个getLastAddId谁来调用?如果是用户侧来调用,怎么保证在新增book之后,调用这个方法之前,没有别的book添加?
- 尔冬橙2019-10-21没想过简单的代码改变蕴含着这么多设计理念和智慧。以前只会死记代码。
- sky2019-10-04以前做移动开发的时候,把改变模型状态的方法都放在modal中了,原来这就是充血模型。谢谢老师,课程越来越棒!
- pyhhou2019-10-021. 平时实现业务没有特别涉及到面向对象的概念,都是设计一个个分离的函数,最多是将职责相近的函数放在同一个目录下,不会包装成类,model 层的操作(DB 操作)也都在一个个函数里面完成,这应该算是充血模型? 2. 看了一下评论以及老师的回复,感觉各种做法都有利弊,思考分析了一下: i) 直接返回所需要的 id:这样是方便,但是违反了 CQRS 的原则 ii) 通过设置全局变量进行交互:如果遇到并行处理的情况会比较麻烦 iii) 命令下达后再调用查询,通过时间戳来找到最近的一次操作:同样要考虑并行处理,而且如何找到最近的一次时间戳也是一个值得思考的问题 iv) 交由客户端处理:会产生其他的问题 总之是要根据具体的场景进行权衡展开
作者回复: 关于 1) 这个理解不对。你可以再阅读一下文章,里面有说贫血模型和充血模型是根据什么来区别的。
- 易儿易2019-09-30看完这讲之后,把上一节给老师提的一个问题自行明白了~ 贫血模型和充血模型区别是Model类是否包含业务逻辑,我之前理解错了,错误的以为是以service层是否包含记录数据的成员变量为区分的(其实这个叫做有无状态) 那这样理解起来的话,平时的springMVC使用action-service-dao三层的都是贫血模式,我在使用面向对象实现业务时把javabean设置为scope=property并把业务逻辑也写在javabean中、不使用三层结构的模式应该属于充血模式。 另外有个小疑问:贫血模式下Model层还剩下什么,参数对象?pojo?返回值对象?Model是不是已经名存实亡了?展开
作者回复: 无论是贫血模式还是充血模式,Model 层包含的内容都是一致的:逻辑+数据,区别是前者把它们分开、分别容纳在无逻辑的 Model 实体对象和无状态的 Service 中,后者则是统一存放在有状态且有逻辑的 Model 实体对象中。你的疑问是贫血模型下脱离 Service 之后的 Model 实体对象吧,它们只剩下数据,而很少包含,或者不包含逻辑,特别是业务逻辑。
共 2 条评论 - 每天晒白牙2019-09-30MVC架构Model层设计时,有贫血模型和充血模型之分 贫血模型:把逻辑从模型实体中剥离出去,放到无状态的service层中,达到状态和逻辑的解耦(我经历过的Model层设计一般都是这种贫血模型) 充血模型:既包涵数据又包涵逻辑,具有完备性和自洽性 你在设计Model层中一般采用哪种模型? 设计接口时有一种模式是CQRS(Command Query Responsibility Segregation,命令查询职责分离) 命令不返回任何结果,但会改变数据的状态,代表写 查询会返回结果,但不会改变数据状态,就是读 在设计接口时,写接口参数可以是对象,读接口参数可以是Query对象,设置查询条件 CQRS这种模式是将读写解耦了 我现在参与的一个MVC的项目是读写接口没有显性参数,都是从请求中获取参数,对于写操作,会自己组装对象,然后调用DAO层接口,对于读操作,直接给DAO层接口传参查询展开
作者回复: 👍
- 靠人品去赢2019-09-27看了这个,我一下理解我们框架提供服务访问的模块为什么命名叫facade。
- anginiit2019-09-27最近几个项目都是springMvc,使用贫血模式
- 許敲敲2019-09-27前端框架AngularJS遵循的是MVC 模式