原文链接 小寒的博客,带你理解更深的世界
面向对象,模块化和MVC
面向对象是指把写程序映射到现实生活,从而一来逻辑性更强,更容易写好代码,二来代码很贴切,通俗易懂,更被人理解,三来更加容易拓展和管理代码。
我们的代码设计应该有很多人,事物和场景,人是管理员,事物是数据库,场景就是业务。
面向对象
写代码就像在模拟现实的生活的处理公务,比如我们可以抽象出一些人帮我们来干活。
文章管理员,负责文章的CRUD,文章分类的CRUD
用户管理员,oauth passport和CRUD
邮件管理员,send email,邮件模版的CRUD
短信管理员,send SMS,短信模板的CRUD
消息管理员,send notification,站内和站外消息模版的CRUD
还有客户端管理员,交易管理员等等等等。。。
分布式开发中,还会借用一些其他服务器的管理员。
当然这里抽象出来多个管理员,还可以抽象出文章存储室,用户信息存储室这样的被管理的对象。
模块化
把代码按照功能和数据分成多个模块,文章模块,用户模块,邮件模块等等,一个模块可能对应多个管理员,比如文章模块里他可能有文章分类管理员,文章管理员,文章查看历史管理员。
模块可以理解为这个世界上有不同的行业,也可以理解为一个家里也有不同的分工,所以分模块可大可小,可以在大的模块里去区分子模块。总之模块是为了解决业务的耦合。就像分行业也是为了解决社会的耦合,但模块之间并不会区分的很彻底,就像各行各业总会有所关联,所以这也需要程序设计者们把握好度了。
模块之间的管理员之间是除了有分工之外,还有很大的合作。比如2C的应用里用户管理员总是需要忙个不停,因为他总要跑来跑去的帮助其他模块去识别用户
我们实现一个很复杂的功能,需求是这样的
某用户的博客发布之后需要其他的人登陆后才可以查看,查看的时候会给博客作者发个短信,告诉博主有人来看你的短信了,再给来看博客的人发个邮件说欢迎光临。
1. user = await UserManager.getByToken(req.header.token)
2. if (user) blog = await BlogManager.getById(req.params.blogId)
3. res.send(blog)
&& SMSManager.send(blog.author.phone, 'blog-be-read')
&& EmailManager.send(user.email, 'welcome')
MVC
这里呢UserManager BlogManager SMSManager EmailManager都是controller,理解为控制数据。
res.send(blog) 中的blog是view,可以理解为要呈现给前端的东西。
这些管理圆管理的模版和数据库则属于model,可以理解为原始的数据。
mvc是应对复杂业务场景的后台最常见的设计模式,会把程序抽象成三层,就像在面向对象里说的那样,一个程序应该有人,事物,业务,其实也可以理解为人就是controller,事物是model,业务是view。对于web后端来说view经常会是web前端。
前端的MVC
类比于后端的MVC
在前端
M指的是后台给的数据,即原始数据
V仍然是要呈现的数据,但是是呈现给用户的界面
C值得是处理后台的数据和view层的交互逻辑
具体实现呢
// model
model = res.data
// controller
view.date = Formater.formatTime(model.date)
view.author = Formater.formatUserName(model.author)
view.blog = BlogController.beautify(model.blog)
// view
document.write(view.author)
document.write(view.date)
document.write(view.blog)
document.write相对于res.send是一样的
前端也会有一些工作人员比如 Formater, BlogController也是控制数据的
是不是和后端很像呀
不同的是前端的view很复杂model很简单,后端的model很复杂view很简单。
前端对MVC的不足
前端的view可能只是在展示数据,这样的网站很适合用MVC,比如管理系统,一个页面一个table的那种。
但也很可能非常复杂,比如在2C的程序中页面可能要肩负各种复杂的操作,操作太琐碎,controller就会变得很臃肿。比如说这个网站里的音乐播放器,要有
上一首,下一首,随机播放,单曲循环,音量,显示列表,显示歌词,关闭歌词,显示列表,选择歌曲,关闭列表,暂停,继续,快进,快退,更新播放时间等等等等的功能。。。这个时候功能这些功能要全部写在controller里同时还要发起请求更新数据,监听时间变化,controller就很复杂。
我们通常都是请求一次后台,然后塞一个列表进去,然后用户切换音乐只是在本地内存里读取数据。
这个时候就会有问题
1. 前端的复杂的操作不像后块化那样可以解耦,前端页面之间,组件之间的耦合应该如何处理
2. 前端的复杂的操作太多了,controller要处理事件还要处理请求,如何减轻维护controller的成本
3. 单页面应用中需要在前端维护一份数据,这份数据只是临时的,不可以放在后端的model里应该放在哪
同时我们也会发现,复杂的业务场景里view和controller的事件处理部分逻辑关系相当密切,所以开发者经常会把controller和view封装在一起,这个时候就出现了组件。
而开发者会在前端暂存一封数据,因为浏览器不用经常刷新了,不需要经常发起请求,因此出现了vm,意指view model。和model的区别就是他是针对view的model。
就这样出现了mvvm和组件化
组件化和MVVM
MVVM
归根结底的说MVC不适合前端的一些业务场景就是因为后端V会相对简单,重点在于解决controller和model的关系。前端的V很复杂,重点在于解决view和controller的问题。
在MVVM中
M不变,可以认为他是数据来源,M很简单,但数据往往不是view需要的。
V是UI和用户输入。面对复杂的用户操作而且要迅速给予反馈,操作和展示往往是同时存在的,比如一个表单就肯定会有表达数据和接受输入两种属性。这就是组件,组件同时具有两种能力,接受输入获取反馈也是MVVM里的第二个V。
VM是在单页应用里出现的一种概念,在单页面的应用里数据在用户不刷新的状态下可以一直暂存在浏览器的内存里,因而把数据请求到本地之后就缓存在客户端的内存里,可以大幅度的复用数据,同时也需要有一层类似于数据库的VM是专门为V提供的model,所以他必须给V更加准确和舒适的数据,以及获取数据和修改数据的方式。同时VM也要减少V里复杂的controller里的api冗余,避免过于繁重的controller,所以和VM也需要负责发起请求。
最后结论就是。
M是response data
V是view + user action controller
VM是store + request controller
这样写的好处有
1. view中加入controller可以增强组件化,view和controller更加密切,可以专注的的表达UI和交互逻辑,把前端的任务大幅度专注在用户体验和UI构建上。
2. 分离model和view之间的直接联系,把和后端交流的任务分配给了view model,确保view拿到的数据更加优雅和易用。
3. 前端暂留一份数据层,供自己的UI使用。同时也把请求数据,处理后台数据的任务给了vm。大幅度减少了controller里的代码。还能起到复用请求和处理数据代码的好处。
组件化
组件化也是面向对象的一种表现。但是组件化和模块化开发在感觉上会又很大的区别。
组件是一种有着强大功能的 "dom" 元素。
组件的任务是用户体验和UI构建。
比如这个博客网站就是由 1. 留言表单 2. 逐个出现的动画组件,3. 音乐播放器,4. 音乐背景墙和歌词组件,5. 博客导航菜单组件 6. 歌单组件 7 歌曲组件 8 导航组件 9 底部组件 10 博客内容 11 博客列表 构成。
我罗列了以下,意思就是说这么大的一个网站其实可以只是这么几个组件而已,这就是组件化的好处。专注构建UI和提升用户体验。
前端组件分类
从bootstrap开始组件分类就已经开始了,通常我们会认为有
antd分为通用,布局,导航,数据录入,数据展示,反馈和其他
这个分类很难以辩驳,个人觉得比较合理,但是这种分类的依据很难说的出来。因为上学的时候,书本里的分类前都会说按照XXX分类可以分为。但是antd这个分类方法就不容易感知到了。
比如通用和数据录入显然并不是一种分类方法。通用是表达组件的使用范围广度,数据录入是按照功能划分的
再比如数据展示和反馈很可能差不多,只是反馈不是直接的数据展示。
但细想以下,这种分类确实也表现出了各个类别里组件的特点。总之分类只是便于理解。因为分不开呀。
我通常会把组件的作用分为以下三种
1. 用于数据展示的
2. 用于接受用户操作的
3. 辅助和增强功能
严谨的说这个是分类组件的功能,而不是给组件分类。而几乎大多数组件都很容易就具有1 2 两种属性。但能看出他们更倾向于那种。
比如
Collapse就是辅助和功能性的,我们市面上见到的都是CollapsePanel这个组件,而Panel是展示数据的组件。
Table就是数据展示的,被我们拓展封装之后呢,我们用到的Table很可能是TableWithPagination,这就让Table就可以接受用户输入了。但Table是更倾向于展示数据的组件
Button是更倾向于用户操作的组件,因为他很能展示文字。
所以可以发现我们用到的组件大多都是有不同的属性的,就像问道里的人物角色一样,三敏一体一力 什么什么的。就是敏捷型的角色。
网站本身是倾向于数据展示的一种应用。因此有些也不好归类为更倾向于某种功能,篇幅有限,总之这个话题想要得到一个比较妥善的答案可以讨论几千字吧。
React不是框架
React是一个构造可组合式用户界面的库,它鼓励创建可重用的UI组件去显示会随着时间而改变的数据。
很多人写react的出发点是错的,和angular,vue出发点并不相同。facebook发明react的原因是在富交互时代的web开发中,如何更好的组织UI是一个很棘手的问题,而通过组件的方式可以很好的解决了这个问题,所以发明了react。
所以说白了react只是一个解决UI问题的工具库而已,使用这个库我们可以很方便的构建一些复杂的交互和样式,并把网站抽象成一个个组件,然后简化web UI的开发,而配合这个库使用解决其他问题的比如react-redux,
react-router等等则是解决web开发的除了UI以外的数据管理和路由等问题的。
如果不能抽象UI,那么用react可能对你来说并不合适甚至很可能是一种累赘,用vue或者ng可以大幅度减少代码量