前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >谈对象/MVC/多端

谈对象/MVC/多端

作者头像
PM吃瓜
发布2019-08-12 17:03:30
7240
发布2019-08-12 17:03:30
举报
文章被收录于专栏:PM吃瓜(公众号)PM吃瓜(公众号)

想想从一个电商网站上买一个东西,“进入首页,搜索商品,选型购买,登录下单,支付完成”,这里面有多少个对象。在我的理解中,对象是一个物,无论是一个真实的物还是一个虚拟的物,但不会是一个动作。比如“登录”是一个动作而不是一个物,所以“登录”不应该是一个对象(类定义),而应该是用户对象里面的一个方法。所以上面那一句的流程中,明显涉及的对象有:商品、用户、购物车、订单,隐含的对象有:页面控制器。

但是,随着业务的复杂,有些动作又会衍生出一个对象,比如当“登录”接入多种第三方OAuth登录时,就会多出一个“OAuth”控制器;“搜索”功能需要比较强大时,必然要加入一个“搜索引擎”控制器。有些对象可能又需要从中拆分出对象,比如“商品”对象可能会需要拆分出“属性参数”对象等等。这个问题似乎很复杂,但也并非无迹可循,我的经验是:从最直接的名词开始规划类和对象,动词和名词内部的名词根据发展需要再进行扩充。

对象规划与职能划分

什么叫职能划分,就是一个对象做它自身的事情。说起来似乎是一个很基本的原则,但是很遗憾,我看过的不少开源PHP项目都没有这个理念。在谈这个问题之前,我想先谈谈嵌入式C语言中的对象。

有研究过C语言和单片机的会知道,C语言里面一个C文件加上相对应的H文件就相当于一个类,是不是感觉和JAVA很像,一个文件就是一个类。当然这个不仅限于这两三门语言,应该是绝大部分语言所共同遵循的规则。在单片机程序开发中,一个硬件模块应该对应一个C和H文件,如一个温度传感器就应该有一个类似于 Temp.c和Temp.h的文件,里面的应该有的方法就是 初始化传感器 和 读取温度。在这个C文件(类)里面,所拥有的函数应该只和这个模块的功能(温度)相关,你可以添加类似于以字符串、符点数、整数返回等等的读取温度方法,但不能加上例如 “符点数转字符串” , “显示温度” 这样的方法。为什么呢?“符点数转字符串”虽然是这里面的一个必须方法,但它是一个通用方法,大部分其它地方都可能会用到,如果是自己实现的话那应该放到一个公共函数文件(如 pubfunc.c)里面去。当然C库里面已经有实现好了的就不要重复造轮子了。“显示温度”看似是一个跟温度非常相关的功能,但是它跟温度传感器并没有关联。你可能会用黑白屏显示、也可能会用彩色屏显示、也可能会用语音播报,这种情况就不能把显示温度放在Temp.c里面,而是应该在业务C文件里把数据读出来运算处理,最后把数据传到对应的显示设备的C文件中去展示。

说到这里,大家可能已经隐约感觉到分层这个理念了,分层稍后再提,先看回网站中应该怎么对象划分。PHP中有函数和方法两种不同的function,函数是应该是公共的,就像前面提到的pubfunc.c一样,还有一些类也是公共的,比如分页类、加密类等,这些文件里面不应该与项目的业务逻辑有耦合关系,应该拿出来给另外一个项目也是通用的。而另一方面的项目功能模块呢,应该是职责明确的,比如用户控制器就应该有读写用户信息、登录注册等等,而不应该有订单数量这种东西。

为什么要MVC和怎么MVC

MVC即是模型-视图-控制器的意思,但实践中,我发现这种统一的MVC说法并不能适应到程序编程的各行各业。毕竟编程有 嵌入式开发、电脑软件开发、手机APP开发、网站开发、游戏开发等等,对应不同的场景应该会有略有不同的具体实现。在此我仅对我自己所使用的网站MVC模式作出介绍,有不当之处恳请提出。

如下图所示,浏览器发出的请求分成两大类,一类是页面请求(红色箭头+蓝色箭头),一类是AJAX纯数据请求(绿色箭头+蓝色箭头),服务器上的代码资源也分为两类,一个是PHP框架的(青底黑框表示),一个是自主开发的(白底蓝框表示)。

1、浏览器发出到服务器,框架通过URL路由分发请求到控制器里,当中可能会做了URL优化什么的。

2、页面请求(根据URL判断)全部转发到页面控制器中(暂时只有IndexController一个),然后调用逻辑控制器;AJAX请求则直接分发到对应的逻辑控制器,逻辑控制器通过一定的策略判断需要AJAX返回还是函数return(如可选参数)。

3、比较简单的逻辑直接在逻辑控制器中处理,直接使用“表模型”访问数据库,我这里说的“表模型”是指没有定义Model类,但是使用对象的方式去操作数据库,通常以表为操作单位,相当于ThinkPHP框架中的M()方法。

4、 对于比较复杂的逻辑,可以进一步封装在一个Model模型中,Thinkphp中称为“虚拟模型”,是指这个模型不一定会有对应的数据表,当然也可能有对 应的表。对于到达何种复杂度就封装到Model中,我经验不足暂无法下定论,因为现在为止我的项目还没有使用“虚拟模型”,也就是说我把MVC三层中把C 层拆分出了两层,而M层至今留空。至于为何这样做,稍后再分析。

5、到这里已经到达了数据库了,取回数据顺着蓝色箭头反方向返回,数据再次 来到了逻辑控制器。如果是AJAX数据请求,则直接echo输出数据或者操作结果,或者用TP内置的ajaxReturn()方法,两者有数据 header的区别,至此AJAX请求就处理结束了,剩下就交给前端JS去处理了。如果是页面请求,则把数据返回给页面控制器,注意这里是函数 return而不是打印输出。

6、页面控制器收集好各个调用到的逻辑控制器返回的数据,利用框架内置的模板引擎或者Smarty引擎,将数据赋值到页面文件中,最后渲染页面输出。

多用户端(模块)和继承

前文再续就书接上一回,上回讲到 我的项目中M层一直为空的。为什么呢?网站这一种程序,通常都会有多端的情况,就是会有 PC端、WAP端、管理端、APP端等等,这个在Thinkphp3.2中称为“模块”。我目前项目中就有 Home(PC端)、Mobile(移动端)、Admin(管理端) 三大模块了。那三大模块就写三份程序吗?显然不应该这样,因为它们之间绝大部分的逻辑是相同的,应该使用继承,而我们的项目中 Home 模块功能最基础、Mobile次之,Admin则是权限最高的模块,大部分写/修改操作只允许在Admin模块中有。所以我项目现有的结构是 Home模块中的类是基类,Mobile继承Home,Admin也继承Home,以后如果感觉有必要的话,也可能会使用一个Common模块,Home、Mobile、Admin都继承于Common。

然后这样的关键就来了,既然有那么多的模块,那么多的类,那么多的模型,如果要新增一个功能那应该写在哪里呢?我们的决定是,很长一段时间内都暂不使用Model类,避免大量继承过来并没有新增功能的“空Model”而导致找查找代码浪费时间;对于新增的功能,如果是一类全新的功能,比如折扣功能,则在几个模块中都新建一个逻辑控制器文件,继承方式同前文所提。新的方法如果可能在PC和移动端都用到的话,就写在Home的控制器里面,如果只有移动端用到的话就写在Mobile的控制器里面,如果是后台管理方面的功能则写在Admin的控制器里面。

实践证明,这样一个决策是可行的,直到现在Mobile模块里面还有半数的控制器是空的(即与PC一致没有新增功能),如果是加上了Model层的话,目测各个类里面的方法会写得很分散,各种继承错综复杂,那些方法要到各个模块下的控制器、模型各种到处找。

我是PHP程序猿,我只有一半对象(PHP的吉祥物是一只象,即半对象,而且PHP可以用或完全不用对象来写程序

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Tech爬虫 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 对象规划与职能划分
  • 为什么要MVC和怎么MVC
  • 多用户端(模块)和继承
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档