关于项目架构与包结构的一些思考

到目前为止做过了很多项目,也写了很多代码,但是对项目的分包一直都是脚踩西瓜皮,滑到哪是哪。网上也有一些总结,但都是经验之谈,业界也没有一个标准供我们参考,在此我也来总结一下自己的经验,对自己来说也有一个划分的标准。

项目分包的意义

科班出生的读者都应该是从计算机的基础开始学习的,那编程语言来说,首先是C,然后是C++,接着是Java,学完Java之后开始选择方向了,有的做Android开发,有的在Web开发。虽然学了这三门语言但不一定都精通,因为学习精力有限,工作中也可能不需要同时精通三门语言,那为什么大学里面会按照这个大纲来给我们上课了,其实这些语言也印证了软件工程这门专业发展的历史。我们知道C语言是结构化语言,没有类、包这些概念,只有方法、命名空间这些东西,我们写的代码基本都在函数里,功能上基本就是函数调函数。如果项目的功能比较少,不需要过多的复用,这些也没什么问题,所以C语言特别适合编写那些短小精悍的程序,比如高效的实现某个算法,用C写一些工具还是不错的。但是现在的项目基本都是Web类型的,业务非常之多,可不仅仅写几个函数就能搞定的,当然把一个功能点写到函数里面也是可以搞定的,代价就是复用率不高,维护起来也很麻烦。后来有了面向对象的语言如C++、Java,他们可以将我们的函数封装到不同的类中,每个类中可以有自己的属性和方法,类可以实例化为对象,不同的对象可以拥有自己的属性,不同的对象之间互不干扰,如果要共享某些属性,还可以用全局变量来实现。类的出现让这些函数有了自己的归宿,不同类封装不同的业务逻辑,但如果类也变很多的话也不方便维护,所以包的出现很好的解决这个问题,但问题来了,有了这项技术我们该怎么使用呢?就像文件可以放在文件夹中我们都知道,但为什么有的人电脑中的文件还是混乱不堪了,主要是因为没有一个划分的规则,他们不知道该如何使用,可能临时需要就建了一个文件夹,然后把当时需要使用的文件放进去。

项目分包的法则

对于分包的法则基本上有两大类,一类是按照项目的架构来到,例如后端常见的三层架构,前端常用的MVC等等。如果使用Spring + Spring MVC + MyBatis来构建Web项目,基本上包会分为controller、service、dao三层,我之前是做Android开发的,对于后端的三层架构并不是特别了解,只是依葫芦画瓢,并且常常将它与MVC进行对比,后来发现两者根本不是一个东西,如果不清楚的读者可以去看看这篇文章《MVC 与三层架构》。当然Java中也有一些不是Web项目,比如向Android这样的客户端程序,还有向Presto这样的大数据查询引擎,项目的功能点不同划分的原则也不同。难道就没有一个通用一点的规则吗?通过我的观察发现,答案是有的。我们通过这些项目的架构图来找一下规律。
下面的图不一定规范,只是为了方便理解而画,其中大的方形上面的文字表示包名,连线的含义我已经标出来了
* Java Web项目

上面是常见三层,我们也是按照这个架构来分包的。Controller层是前端控制器,根据不同的URL来执行不同的业务逻辑,Service层就是编写业务逻辑的地方,也是代码量最多的层,Dao层就很好理解了,主要负责数据持久化与读取操作,跟数据库相关。当然一个项目不止上面三个包,我们可以根据具体的需求来添加相应的包,比如工具类所在的包,实体类所在的包等等。

  • Android项目


我们可以看到Android项目中的MVC与上面三层架构好相似,因为他们都是三层,但在MVC中service、dao层被划分到Model模块中了,三层架构中的Controller和MVC中的Controller作用是一样的,主要是界面与业务逻辑之间的桥梁。至于多出来的Callback接口主要用于事件监听,设配器之类的,因为Android是基于事件的应用程序,数据的处理都是异步的,处理结果不能由函数返回。讲到这里我说一下个人关于三层架构与MVC的理解吧:


我们的代码主要干三件事,第一件是界面管理(显示器),第二件是数据的处理或者加工(CPU),第三件就是数据的读写(磁盘)。现在的软件架构主要分为B/S和C/S两种类型,但我觉得两者本质是一样的,因为B/S中的浏览器也是Client。它们主要的区别在于C/S中的客户端将部分代码放到了本地,这些代码很少进行更改,客户端运行时只需要取经常变动的数据即可,而B/S中的Browser不一样,它不仅能请求数据,还能将这些数据当作代码运行起来,当然在Java中也可以动态加载服务端的代码,但这个效率肯定没有浏览器高,客户也不接受,这也是解释型语言的优势,效率虽然低一点,但可以立即运行,不需要编译加载这些复杂的流程,如果Java是解释型语言也就不会出现JavaScript了吧。从上面的分析可以看出软件是由代码组成的,根据代码分布的位置划分为不同的架构,当然这个划分是粗粒度的,像界面管理这类的代码必须要放在客户端或者传输到浏览器中执行,服务端是没法做的,像这些主要编写界面管理的人员成为客户端开发人员或者前端开发人员,语言并不是区分客户端、前端、后端开发的标准,而是看他们所做的工作。像数据处理或者加工客户端、前端也可以做,但不能所有的数据它们都适合处理,因为要考虑安全、效率等因素,即使客户端、前端适合处理开发人员也不愿意,毕竟人的精力是有限的。上面说了这么多,主要是想让读者明白,架构也好、设计模式也好都是对代码的划分,使其易于扩展,方便管理,这才是他们的本质,不同的项目要选择相应的架构。三层架构和MVC也是对代码的划分,三层架构主要划分为控制层(controller),服务层(service),数据访问层(dao),三层架构中界面管理的代码是在控制层的,数据处理或者加工就在服务层,数据的读写就在数据访问层了。那么MVC是如何划分的呢?MVC中将界面管理代码从三层架构中的控制程中拿出来了,用V来表示,但是服务层和数据访问层在MVC中就合并成了M,所以MVC对三层架构中的控制层进行了拆分,对服务层与数据访问层进行了合并。这个区别我也是琢磨了很久才弄清楚,因为以前对架构也没有思考过,别人怎么划分的我也照样划分,至于为什么也没深究,毕竟这些都是经验,开发人员长期总结的结果,错不了。那么为什么会出现这两个概念呢?我在网上搜索也没有得到答案,只知道MVC出自设计模式,三层架构出自Java EE企业级开发,设计模式倒是学习过,至于Java EE企业级开发我也没经历过,自己觉得是超大型项目的开发标准,不知道是否应该看看相关方面的书籍。对于Android开发人员来说很简单知道MVC就行了,按照这个结构划分问题不大,如果觉得不合适也可以换换MVP,MVVM这类的架构。但是后端不一样了,我起初开发SSM后端程序的时候,有一个Spring MVC的框架,给我第一眼的感觉就是后端的代码也用的是MVC的设计模式?但当我看到controller、service、dao这些包名的时候我就糊涂了,因为我不知道这是三层架构的分包方式,还傻乎乎的认为controller对应MVC中的V,service对应C,dao对应M,那时总感觉怪怪的但又无法解释清楚。为啥后端的代码中既有MVC,也有三层架构呢?那是因为MVC适用于带界面应用的开发,三层架构适用于数据处理应用的开发,从它们的侧重点就知道MVC适用于界面相关代码较多的项目,而三层架构将适用于数据读写较多(主要是与数据库打交道,虽然客户端也可以与数据库通信,但是两者的代码不是一个数量级的)的项目,因为Java Web项目既有网页还有数据库的读写,所以既用到了MVC也用到了三层架构。那么Spring MVC和MVC又是啥关系呢?MVC是思想,SpringMVC是具体的产物,是一种技术,是MVC的一种实现并且用与Java Web开发,思想是通用的,技术就只能用于特定的平台了,SpringMVC应该就无法应用于Android平台了吧。


框架型项目

除了上述常见的两种应用型的项目,还有框架型的项目,他们具有更广的适用性,他们就不一定是三层架构这么简单了,比如高大上的分布式架构,使用的技术也不一定是SpringMVC,向这种类型的项目因为属于框架,整体的结构不可能发生变化了,我们要做的就是第一步怎么做,第二部怎么做,按照规则编写代码即可,所以它们这种类型的项目一般是根据功能来划分包,如果包比较多就划分成子模块。

总结

上面说了这么多,无论是从架构还是从技术层面,如果你的项目结构清晰,依赖关系明确,可以使用按照功能模块来划分包,如果依赖关系混乱,模块众多,还是按照架构来划分吧,通常来说Java Web项目都是按照三层架构来划分包的,这也符合主流的划分原则,因为大型项目的需求是不断变化的,我们只能选择变动小的方式来划分,项目的机构一般是不会轻易变动的,这种划分的缺点就是编写一个模块需要打开N多个文件夹,按功能点划分你就没有这样的烦恼,但是如果某个功能点划分到了其它模块,你的代码也得移动到其它包之下。如果上面的表达有误请帮忙指正,谢谢!

在 “关于项目架构与包结构的一些思考” 上有 2 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注