【心得】编写服务端的相关设计心得及体会

  最近接手公司服务端接口的相关编写工作,遇到了一些问题,提出了一些想法,讨论了一些问题,与项目经理在方案选择上有了一番争吵(当然,这种争吵是家常便饭的事儿)。特此有了一些心得体会。

方法入参的设计



  我们在设计程序的时候,如果使用常规的分层模型,既Controller、Service、Dao,来对项目进行分层,一定会遇到一个问题,就是不同层及之间,数据传递,即每个方法的“入参”应该怎么设计。

  我曾待在一家从事银行系统开发的公司,项目有一个很大的特点,它并非使用C、S、D来进行分层开发,当然这不是重点,重点是它虽然使用Java,但是大部分不以面向对象的形式来编写程序,项目中随处可见的是static的静态方法,几乎什么功能都可以用静态方法来完成,我的理解它已然是一个用java以面向过程的思想开发的项目。这个项目在方法之间传递数据时,不适用对象封装,而是采取多个入参的形式,所以很常见的就是要一个方法,有N多个入参,5个是常见、10个都不特殊。这种方式来编写方法,有一定的缺点:

  •   在阅读代码的时候,经常会不明白参数的意义,而需要仔细的去看javaDoc上的注释,影响效率;
  •   调用一些工具时,因为不是以面向对象的方式去设计程序,所以所有变量的作用域自然只在方法体内,于是对于一些需要设置参数的工具,简单的例如:分页工具,就需要通过一大堆的入参,经常会搞不懂入参的意义,每次调用起来需要重新设置一大堆的参数值;或者使用一个Map来装载这些参数,这样带来的问题就是你甚至不知道有什么参数需要设置,经常会出现错误。

  当然,会用这种方式来设计程序,当初项目经理的意思是说:由于变量的作用域仅仅存在于方法体内,当方法执行结束以后,变量就会进入销毁,能快速的回收内存。虽然我并没有真正的去测试过这个观点的正确性,但就我对JVM的GC机制来说,这种做法,是不是会造成大量的垃圾对象,这样GC就会频繁被调用来回收这些对象,这反而是增加了内存的消耗。

  有了这次经验,我自然是非常反对为方法设置大量参数作为入参,以对象作为数据载体,进行传递,我认为才是最好的方式。但,依然产生了一些问题。

要用什么对象来传递参数?



由于种种原因(这里就不需要深究为什么了),我们项目在设计接口的时候出现了一个讨论的命题:

  要用什么来接收来自前端的请求数据?又如何把前端想要的数据,按照前端需要的数据接口形式,传递出去?

简单介绍一下会有这个问题的背景:

  我们在设计接口的时候,往往会遇到这种问题:一个数据接口所请求的数据,分别来自于不同的数据库表,而同时它们也可能在程序中,是分别属于两个不同的对象的成员属性,那这个时候,我们要怎么去设计接口,如何返回数据?    

我先来揭晓一下这个讨论结果的最终的决定:

  我们项目因为不希望不同层在传递数据是,不知道具体要传递的数据内容,所以不希望我们使用Map来作为载体,而尽可能的使用对象来做。这一点我是没有异议,表示很赞同,因为我曾就深受其害,Map真心不认为是一个适合用于传参数的载体,当然这也不是一棍子打死,只是最好不要使用。但经理让我们这么做,新建一个特殊的对象,这个对象没有任何实体意义,仅仅是为了接口的形式,而去设计的Class,然后把从数据库中查询出来的已经映射成实体对象的数据,拆包,根据对应的成员对象再组装到这个新的对象当中。这句话可能不好理解,我举一个例子:

  有一个实体对象(我们叫他Class A),它有10个成员属性,分别是:a、b、c、d.....;但是某个接口仅仅只需要请求这10个成员属性中的某3个属性,于是我就要为了这个接口,专门创建一个类(我们叫他:Class B),这个类只有3个成员属性,没有错,Class B 只不过 是Class A的一个子集。

  我们使用的是Mybatis框架,本身查询出来的数据,就已经是一个实体类,具有最全的属性,然后我要把这个实体类的每个接口请求的对应属性都get出来,然后再set到这个新类当中。我把这个get的过程,称作“拆包”,set的过程,称作“装包”。

当然我不认为这是一个好的设计思路。

  1. 因为这么做首先是每次新增一个接口,就要新建一个class,这种做法本身就违反了程序设计的复用性原则,每个class几乎都是无法复用的。
  2. 每个接口,每次请求,都需要做一个多余的get、set的动作,这个动作,局部看起来也不是很多操作,但是放到一个高并发的环境中,我认为真的代价很高。
  3. 从前端接收请求参数时需要创建一个特殊的,只有请求参数的载体对象,数据库查询后需要创建一个映射实体的对象,然后接口返回也要再来一个专门的对象,一个请求最少也需要至少3个对象来完成,一次请求,产生3个对象要等待GC回收。

使用实体类作为数据载体



  我们之所以会选择这种方式,也是有原因的,我们是以json形式返回数据,spirngMVC可以添加一个过滤器,把null值的属性都去掉,所以我提出的观点自然是通过实体对象来作为数据承载,一次简单请求由一个实体对象来承载所有的请求数据,并且承载数据库返回的查询数据,这样一次简单请求自然就不会产生什么多余的对象和不必要的操作,然后通过json的not_null过滤器,把null的属性过滤掉,这样接口就干净简洁。

  而且我们基本上都是以面向对象的方式来设计程序的,关系型数据库也基本上是根据实体来设计表结构,所以表和实体的映射非常容易设计,关联性很强,每次数据传递接口也不会很多参数,因为毕竟一次请求所需要的数据,跟他发来的请求条件,都会有一定的关系,所以依据对象之间的嵌套关系,实体对象很容易作为数据载体进行方法之间的传递。

  但是,这样不代表就完全没有问题了,而这个问题我也不知道如何解决:

  一个对象假设有10个成员属性,而一次请求,有1个以上,但可能也就是2个或3个数据参数作为查询条件,那我却要为了这2-3个参数,去实例化一个具有10个成员属性的对象,虽然另外的7-8个成员属性可能没有值,但是不代表他们不消耗内存。

  这个问题我一直都想不通,是否有可以解决这类问题的办法?项目重构,将经常调用的参数进行抽象成父类确实能够缓解一点,但也不能完全避免这种内存的浪费。

  

就算没有值,也要设置一个默认值来表示



  但前端那边提出了这样一个问题,有的请求,某些字段确实会有出现没有值的情况,即null的情况,那就会被过滤掉,结果键值都没有,那我就不知道到底是后端没有数据,还是程序出错。于是提出,就算是null,也不能把键值去掉。

  其实当时我被这个问题问蒙了,也没有什么好的解决办法。但是回头想一想。。。如果后端返回null,你前端就一定能够确定,不是程序问题么?如果程序出问题,一样会出现null的返回结果,数据设置失败了还不也一样会值为null。要分清楚这个问题,就要能够确定这个值是否是“人造”的数据。

  所以我认为,不管是何种数据类型,都应该尽量(同样不能一棍子打死,有的数据确实没办法设置这种默认值)去设置一个默认值来作为这个数据没有值的一个表示,如时间可以设置为00:00:00,正整数可以设置为-1。还有一些字段必填的自然要做好必填项的校验。

  

  

时间: 2024-10-14 00:44:58

【心得】编写服务端的相关设计心得及体会的相关文章

通过WebSocket实现实时通讯C#语言编写服务端

无意中发现js有webSocket对象于是百度了一下客户端代码与服务端代码没有现成的 有的就有一些简单了连接例子有的还不好使 于是就自己整理了一下 c#编写的服务端代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; using System.Text.RegularExpression

移动端与服务端通信流程设计

转自:http://blog.snsgou.com/post-766.html 针对 --->非开放性平台 --->公司内部产品 接口特点汇总: 1.因为是非开放性的,所以所有的接口都是封闭的,只对公司内部的产品有效: 2.因为是非开放性的,所以OAuth那套协议是行不通的,因为没有中间用户的授权过程: 3.有点接口需要用户登录才能访问: 4.有点接口不需要用户登录就可访问: 针对以上特点,移动端与服务端的通信就需要2把钥匙,即2个token. 第一个token是针对接口的(api_token

使用openssl编写服务端和客户端程序

1.使用相同的ca生成两个证书,一个是server.cer,一个是client.cer,注意生成server.cer的时候必须指明证书可以用于服务端的. 服务器代码: #include "openssl/bio.h" #include "openssl/ssl.h" #include "openssl/err.h" #include <cutil.h> #define EXIT_IF_TRUE(x) if (x) \ do { \ f

阅读高手编写的类似QQ聊天的服务端代码DAO设计总结

1.数据访问层DAO的设计(已该工程为例) (1)首先定义一个接口,规范算法框架.(若子类和基类有很多公用的东西,则应该设计成抽象类) package com.way.chat.dao public interface UserDao { //注册成功返回用户id public int register(User u); public ArrayList<User> login(User u); public ArrayList<User> refresh(int id); pub

安卓升级服务端和客户端设计

三.服务器端和客户端设计 服务器端设计: 设计方法应该有很多,下面介绍我的一种方法: a.首先在服务器项目下建立一个文件夹来存放APK安装文件: b.其次在src下建立一个资源文件,apkVersion.properties,属性定义如下: [plain] view plaincopyprint? apkVersion=1 存版本号apkSize=550kb 大小apkPath=http://xx8080/srv/apk/Demo.apk 升级文件 c.定义一个servlet来获取资源中的信息:

使用Thrift RPC编写程序(服务端和客户端)

1. Thrift类介绍 Thrift代码包(位于thrift-0.6.1/lib/cpp/src)有以下几个目录: concurrency:并发和时钟管理方面的库processor:Processor相关类protocal:Protocal相关类transport:transport相关类server:server相关类 1.1 Transport类(how is transmitted?)负责数据传输,有以下几个可用类:TFileTransport:文件(日志)传输类,允许client将文件

服务端测试之接口测试用例设计

小伙伴们大家好,上一次和大家分享了<服务端测试之接口测试初探>,讲了一些接口测试的基本概念和理论知识.在上次的分享中,简单提到了接口测试用例设计包含的几个方面.本期我将在上次分享的基础上,和各位小伙伴一起具体看看这几个方面都是什么,在实际的项目中应该如何使用. 一.功能性用例设计 之前讲过,服务端的接口是和客户端的功能相对应的,对功能的验证,可以参照接口说明文档来进行.概括起来讲,就是我们需要验证接口说明文档中提到的各种情况,保证这些情况下接口的返回和最初设计的是一样的,这样我们就可以认为该接

几十万人同时在线的直播间聊天,如何设计服务端架构?

一个热门视频直播间人数可能达到几十万甚至上百万人,几十万人发消息,几十万人接收,流量相当惊人,那么服务端要如何设计才能保证系统流畅?本文作者将结合他在网易云信多年IM开发的经验进行深度分析. 推荐阅读 高并发IM系统架构优化实践 IM即时通讯:如何跳出传统思维来设计聊天室架构? 聊天室架构应满足哪些条件 高可用:任何一个节点故障都不应该引起服务不可用: 易扩展:具有水平扩展的特性,对不同量级的在线用户数都有应变的能力: 高并发低延迟:能支持大量的用户同时收发消息,消息从发出到送达所有在线端的延时

webservice -- cxf客户端调用axis2服务端

背景: 有个项目, 需要由第三方提供用户信息, 实现用户同步操作, 对方给提供webservice接口(axis2实现)并也使用axis2作主客户端调用我方提供的webservice接口 起初, 由于项目使用了spring, 且spring可与cxf较好的集成, 所以也就选用了cxf, 可问题随之出现, 接口可以调用到, 接口的具体方法也可以调用到, 但是, 1. cxf作为客户端, 获取服务端返回值时均为null. 2. cxf作为服务端, 获取axis2客户端传来的参数时, 也均为null.