【代码规范】我所理解的代码规范
本人是一名从事java开发2年的小菜,常用MVC框架为spring,在这里只是想谈谈我所理解的代码结构。若说的不对请指出。
我们在写程序的过程中,普通的代码层次都是会区分成controller,service,dao这三层结构,这里主要想聊一下我是怎么样理解这三个层次的,以及他们分别应该处理什么样的事情,担任什么样的角色。
此处说明一点,这些规范只是本人在coding过程中自己体会总结出来了,可能现在不全,可能现在又不足的地方,还希望各位指出。
首先简述一下controller和dao,controller这个C在众多的MVC框架中被广泛使用,controller的翻译过来就是控制器,控制器在整个代码结构中主要担当请求转发,访问权限处理,参数处理等。而dao则是负责对于数据库的基本操作。这里就不多做介绍了。
然后主要说一下service,个人觉得service层,是非常强大的一层,也是在三层结构中最重要的一层。绝大部分业务逻辑,数据库的事物,以及数据权限,可能都会在这一层去实现。那要怎么样才能写出一个优秀的service呢?我们来一起探讨一下。 service翻译过来就是"服务",那作为一个好的服务,是让客户端可以更加便捷,方便的使用他。我们先看如下例子:
1.注意service层对外的方法
//基本插入操作 public void insert(Object obj){ dao.insert(obj); } //提供给客户端使用 public void insert(String content , String contentType){ Object obj = new Object(); obj.setContent(content); obj.setContentType(contentType); dao.insert(obj); }
这两段代码的区别是参数的不同,对于客户端来说,如果提供的方法参数是一个object,客户端并不知道需要放入多少个值,但是如果吧参数完整的列出来,客户端可以很明显的知道,当我执行insert的时候我需要给多少个值,可能有人会说,我一张表字段特别多,但是当第一次插入的时候,其实字段并不会很多,可能很多值在插入的时候是不需要的,有一些值是默认的,这种完全可以再我们service中就封装好,使用者无需知道。
2.在方法中尽量使用枚举
public Object getOrderByType(OrderType orderType){...}
public Object getOrderByType(Integer orderType){}
我们在数据库中,很多时候会以某个数值代表某个含义,比如1代表是已付款的订单,2代表未付款,等等。当你提供的service的时候,如果希望客户端使用方法的时候传递的是0,1,2的话其实是很不友好的,因为在客户端使用的时候,我并不用知道0,1,2分别代表什么,可能还需要去看数据字典。但是如果提供的是枚举的话,客户端可以很鲜明的知道,这个方法需要什么。
其次,因为规范了入口,service的方法体中得到了保障。如果外部传入的Integer因为某种原因传入的数值并不是方法体内想要的内容,还需要去处理参数,但是这个活不应该是service干的。但是使用枚举可以很好的避免这个问题。
3.入口需要统一
在我们的service中,我们可能会有很多种insert,很多种update,这是正常的,因为我们需要处理不同的业务,可能会有很多种方法的重载。但是这里需要提到一点。所有的对于数据的操作,建议都调用service中最基础的insert,如:
//基本插入操作 public void insert(Object obj){...} //插入信息和详情表 public void insertInfoAndDetail(Object obj){ this.insert(obj); otherService.insert(...); }
如上的例子,在insertInfoAndDetail方法中,其实可以调用dao的insert但是我们还是期望可以统一入口,全部调用service中的insert。
4.方法名的注意
service的提供方法中,最重要的就是方法名。可能有人说,我注释写的很好,很全。但是一般的coder首先第一反应是看方法名,比如一个get方法中执行了一个update,但是在注释上写了“此方法是更新操作”,我相信10个人中8个人会认为他是查询。记得以前在<<如何编写优雅的代码>>中提到,方法名就是最好的注释。这点无容置疑。
这里还要提一点,方法名要尽量的具体化,如果不是通用的业务,不要使用通用的方法名,我曾今看到如下代码
//查询XXX类型商品的图片 property List<Picture> getPictureByGoodsId(Integer goodsId){ Map<String,Object> params = new HashMap<>(); params.put("goodsId","goodsId"); params.put("pictureType",PictureType.XXX); }
此方法仔细一看,在注释有些是查询XXX类型,但是方法名完全体现不出来,很容易误导使用者。独立的业务需要独立的方法名!
5.具体方法只做本方法的事情,不要让你的方法“做太多”。大家看如下代码。
//代码1 public void insert(Order order){ //当满足某条件下,订单直接付款通过 if(xxx){ order.setPayedStatus("已付款"); } dao.insert(o); } //代码2 public void insert(Order order){ //当满足某条件下,订单直接付款通过 updatePayed(order.getId()); dao.insert(o); } //更新是否付款 public void updatePayed(Order order){ if(xxx){ order.setPayedStatus("已付款"); } service.update(order); }
看如上两段代码,可能有人会说,如果用第二种代码执行会多操作一次数据库,但是从我的角度出发,我宁可多操作这一次数据库,而不是吧插入和更新的业务同时执行。因为插入的时候只需要管插入的业务即可,他无需关心更新付款状态有多少业务存在。如果说之后更新付款状态以后需要添加业务代码的话,我们只需要修改updatePayed方法即可。也反应出我在第3点(入口需要统一)中提到的。