编写出规范,易读,优雅的代码能够大大方便代码的维护,推荐相关书籍——代码整洁之道。
目录
3.行数不易过多,50行左右,最多不过100行,一般超过100行,说明方法内部有代码需要整合成另一个方法,当然,赋值超过100行不算
一、变量名
1.名字和变量的意义要一致;
2.一个变量,不能当成俩个变量来使用
场景:在一个方法内,程序员发现有一个字符串变量只有在最开始或者某一段中使用到时,为了充分利用这个变量,不再重新声明新变量,而是一直对该变量进行操作。
private String getTempString(String type)
{
if ("xxx".equals(type))
{
return "";
}
String temp = "xxxxx";
//下面全是对temp字符串进行操作,type已经没有用了
return temp;
}
对于上面那种情况,可能少部分程序员发现type只有在最开始用到了,而之后从来没有使用,那么他可能会选择不声明temp变量,而使用type来操作,这个时候,虽然你减少了局部变量的个数,但是变量的意义在这个方法内确有不同的意义了,那么对于后来维护代码的人来说,这是很痛苦的,并且这个方法的意义就是获取temp字符串,你返回一个type字符串,虽然可能最后的值相同,但是对于第三者来说,会觉得很矛盾。比如,上面的代码写成这样:
private String getTempString(String type)
{
if ("xxx".equals(type))
{
return "";
}
type = "xxxxx";
//下面全是对temp字符串进行操作,type已经没有用了
return type;
}
二、方法
1.只关注一件事,那就是这个方法名所赋予的事
2.参数个数要少,这样耦合性就低,规范要求是少于5个
3.行数不易过多,50行左右,最多不过100行,一般超过100行,说明方法内部有代码需要整合成另一个方法,当然,赋值超过100行不算
4.方法内位于同一抽象层级
举个例子,如下:
private void deleteSomeThing(String user, String startTime, String endTime)
{
if (user.length() > 5)
{
user = user.substring(0, user.length() - 5);
}
Date startDate = simpleDateFormat.parse(startTime);
Date endDate = simpleDateFormat.parse(endTime);
Calendar startCalendar = Calendar.getInstance();
startCalendar.setTime(startDate);
/**
* xxxxxxx
* xxxxxxx
* xxxxxxx
* 一系列对user,startTime,endTime的操作,然后最后得到一个删除条件
*/
String condition = "xxxxxx";
//最后通过mapper或者dao操作数据库删除数据
mapper.deleteSomeThingByCondition(condition);
}
像这种,直接在一个方法内,写了太多的操作,如果逻辑复杂一点,行数就会飙升,代码可读性也变得很差;如果修改如下:
private String getUserCondition(String user)
{
if (user.length() > 5)
{
user = user.substring(0, user.length() - 5);
}
//xxxxxxxx
//xxxxxxxx
//xxxxxxxx
String userConditon = "xxxxx";
return userConditon;
}
private String getTimeCondition(String startTime, String endTime)
{
Date startDate = simpleDateFormat.parse(startTime);
Date endDate = simpleDateFormat.parse(endTime);
Calendar startCalendar = Calendar.getInstance();
startCalendar.setTime(startDate);
//xxxxxxxx
//xxxxxxxx
//xxxxxxxx
String timeCondition = "xxxxxx";
return timeCondition;
}
private String mergeCondition(String userCondition, String timeCondition)
{
String allCondition = "xxxxx";
return allCondition;
}
private String getConditions(String user, String startTime, String endTime)
{
String userCondition = getUserCondition(user);
String timeCondition = getTimeCondition(startTime, endTime);
String condition = mergeCondition(userCondition, timeCondition);
return condition;
}
private void deleteSomeThing(String user, String startTime, String endTime)
{
mapper.deleteSomeThingByCondition(getConditions(user, startTime, endTime));
}
其实,如果能够实现,每个方法抽象层级相同,那么方法的其他规范就很容易满足,像上面这种修改,通过抽象层级的划分,每个方法的行数一定会很少,参数也不会很多。虽然多出了很多方法,但是每个方法干什么都能一清二楚,并且可能不需要你阅读方法内的代码,你只需要看方法名就知道作用了。不过这个列子比较极端,拆分了很多方法,具体需要如何拆分,拆分多少个方法视情况而定,比如整个操作代码行数都不过50行,那么全部写在一个方法内也可以。
那么再回到抽象层级来讲,以这个列子为例,
第一层:deleteSomeThing(String user, String startTime, String endTime)
deleteSomeThing方法内部层级只有mapper层,和条件变量(可以把getConditions返回值返回给一个条件变量,然后mapper传入这个变量),因为当你要删除某些数据的时候,最直观的就是,调用mapper,删除满足条件的数据,至于,这个条件是什么,怎么获取,这个层级是不关心的;
第二层:getConditions(String user, String startTime, String endTime)
这个层级只需要返回条件给上一层调用,不需要操作参数来合成条件(当然,如果逻辑简单,也可以在这一次层级操作参数),所以他只关心条件本身,不关心条件如何操作。这个方法内部就只有各种已经处理好的条件变量。
第三层:
getUserCondition(String user)
getTimeCondition(String startTime, String endTime)
mergeCondition(String userCondition, String timeCondition)
这三层都是操作参数以返回目标条件格式,所以,这三层关心的就是对参数的操作。
三、实体类
至于数据库交互,与数据库表或者文档中的字段一一对应,不多不少;在新增数据,更新数据时使用该类。
四、模型类
与前端交互,前端需要哪些属性,模型类中就应该有哪些属性。
其实大部分情况系,模型类和实体类的属性字段相差不大,或者说可能一模一样,那么在这种情况下有必要分实体类和模型类吗?答案是肯定的,之所以有这两个层级,就是为了将保存数据和前端交互分隔开。考虑一种情况,当前实体类和模型类字段一模一样,那么不久之后因为业务的变更,模型类字段突然发生了大改变,但是保存的数据还是和之前一直,那么,如果最开始不区分实体类和模型类,都用同一个类,这个时候这个类的定义就会模糊了,因为这个类的字段是数据库表中的字段和前端需要的字段的融合,而且因为修改了这个类,可能会对于数据的保存和查询都产生影响。但是如果一开始就区分了,那么只需要修改模型类,对保存数据这部分是没有任何影响的。
五、服务类
提供一组功能,完成某个模块的所有功能,主要是对业务逻辑的处理
六、Controller类
与前端交互,只负责对前端数据的传递,接收和返回,不参与数据的处理、加工
七、mapper或者dao类
只与数据库交互,尽量不参与数据的加工。