文章目录
-
- 程序数据的特殊性
-
- 场景一:外部数据
- 场景二:内部数据
- 场景三:软件一般意义上的场景
- 程序场景的特殊性
- 针对程序结构的必要说明
- 针对应用场景的特殊性
程序数据的特殊性
- 数据库
- 第三方缓存
- 第三方服务
如果从程序设计角度来看,大家公认的程序本身可以分成两部分:数据结构 + 算法。对于后端来说,又可以分为三个场景。
场景一:外部数据
在该场景中,数据结构就是数据表的设计,包括:关系型数据表及非关系型数据存储的设计;而算法就是如何操作这些数据。该场景下,数据结构的设计是最关键的。
场景二:内部数据
在该场景中,数据结构就是实现一项功能所涉及到的类之间的结构。即通过定义每个类的成员变量和方法,规划类之间的组合继承等关系来实现数据结构的整体设计。
而算法,则是实现一个功能时内部对象之间交互的流程,通常可以使用UML的时序图表现。
该场景下,二者平衡。
场景三:软件一般意义上的场景
即软件开发人员通识的算法与数据结构的概念。系统中涉及到一些特殊功能项的时候,会采用特殊的处理方法来实现优化的目的。该场景下,偏向于算法设计。
后端程序与其他应用程序最大的区别之一就在于后端更偏向场景一,即外部数据非常重要,所以在一定程度上来说是面向数据库编程。
程序场景的特殊性
后端每个API都是可以出现并发场景的,即一个API可能被多个应用同时访问,并且这个访问量可能会变得很大。不像APP、web等客户端程序,虽然会遇到并发问题,但不是核心。
基于性能的考虑,如果频繁创建的大的对象,由于对象占用的是堆内存空间,而堆内存空间正是垃圾回收器的主要处理点。在并发数高的场景下,会导致频繁执行全量垃圾回收操作,即内存频繁出现大块的搬运处理,最终表现就是API响应卡顿或者内存溢出导致服务器挂掉。
正是由于存在上述的特殊性,使得后端程序在设计时会优先考虑避免大对象的频繁创建,也就是最好只创建一次,通过复用该对象实现业务处理(这里,大和频繁是两个重点)。那么这一方案引出了两个关键点:
- 大的对象本身不能保存状态,否则会出现并发数据共享的问题;如果加锁处理,会严重影响程序性能(并发数高的情况下)。
- 针对这类对象,保证运行期间只创建一次,即类似于单例模式实现,这点Spring已经提供支持,这也是为什么Spring托管的对象默认都是单例的。
这也就是为什么目前开发后端项目时,开发人员所熟知的Controller、Service、Dao这三层结构的类,他们的实现类都只创建一个对象,并且不保存状态(即不存在保存数值的成员变量)的一个重要原因。
至于这三层结构的划分,则是基于后续体量大的一种考虑方案,并不是最优解,但是最常见的分层。
针对程序结构的必要说明
基于上面两个解释,总体来看:
将程序的核心层级划分为常见的三层,并且保证每个类都是单例类(Spring 已经帮我们实现了)。
针对一般性的CURD操作,只要保证数据表设计良好即可。设计良好意味着三个方面:实用性、扩展性和性能优化。
针对复杂的业务设计,就要考虑类之间的耦合性、扩展性等。并且,会频繁创建并且不需要保存状态的类能设计成单例类(加上 @Component注解)就设计成单例的。
当然,上述只是理想下的实现,涉及到实际业务还是要符合实际的复杂情况。
针对应用场景的特殊性
为了保证连贯性有必要补充说明一下后端应用场景的特殊性。后端所提供的服务具有两大特性:
- 持续服务不间断
- 不论服务多少客户,对外表现都是相同的
由这两个基本点出发,引出了服务端的一系列问题:要想保证不间断服务,必须通过各种层面的冗余措施来提升系统的可靠性;要想保证性能平稳,即对外表现稳定,那么就要结合实际场景针对不同子系统设计压力处理的方案。而服务整体的可用性,则需要监控系统和测试系统以及发布系统等提供保障。
所以,我们一般设计从三个角度出发:
- 软件本身的设计
- 系统的设计
- 项目整体的设计
文章知识点与官方知识档案匹配,可进一步学习相关知识Java技能树首页概览92065 人正在系统学习中
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!