文章目录
- 前言
- 其他类型的规范
- 长函数
- 长参数列表
前言
做Java开发的,大多数可能都有看过阿里的Java后台开发手册,里面有关于Java后台开发规范的一些内容,基本覆盖了一些通用、普适的规范,但大多数都讲的比较简洁,本文主要会用更多的案例来对一些规范进行解释,以及结合自己的经验做补充!
长函数
我知道有很多公司都有对一个方法的行数有一定的要求,比如不能超过50行、甚至20行,我觉得这样不分场合的硬性要求并不合理,我们应该搞清楚长函数会带来哪些问题?由问题为出发点,去检查方法的行数,有时候10行可能都写的不好,有时候即使50行了但也没问题,像Sping、MyBatis源码中超过50行的方法也有很多。
其实大多数造成长函数的原因就是封装、设计的不够,导致代码的可维护性变差,对重复的逻辑没有封装,就像看C语言的代码一样,面向过程,平铺直叙的完成整个业务逻辑。
几行代码也并不一定表示没问题
public static void longMethod(String userId, BigDecimal price) {
// 判断用户是否是VIP
User user = userDao.getUserByUserId(userId);
int memberAttr = user.getUserMemberAttr();
double discountPrice;
// VIP用户打8折,其他用户打9折
if (memberAttr == 1) {
discountPrice;= price.multiply(new BigDecimal(8)).doubleValue();
} else {
discountPrice = price.multiply(new BigDecimal(9)).doubleValue();
}
}
抽象出通用逻辑
// 根据用户ID获取用户会员属性
private static int getUserMemberAttr(String userId) {
User user = userDao.getUserByUserId(userId);
return user.getUserMemberAttr();
}
// 根据会员属性计算折扣价
private static double getDiscountPrice(int memberAttr, BigDecimal price) {
double discountPrice;
if (memberAttr == 1) {
discountPrice = price.multiply(new BigDecimal(8)).doubleValue();
} else {
discountPrice = price.multiply(new BigDecimal(9)).doubleValue();
}
return discountPrice;
}
最后具体业务逻辑应该是这样
public static void longMethod(String userId, BigDecimal price) {
// 获取用户会员属性
int memberAttr = getUserMemberAttr(userId);
// 根据会员属性获取折扣价
double discountPrice = getDiscountPrice(memberAttr, price);
}
还有很多方法较长的原因是因为不是出自同一人之手,意思就是,前人写的代码不了解逻辑、业务不敢随意乱动,只能继续叠加功能。
美国童子军一条简单的军规:让营地比你来时更干净。
长参数列表
这一条规范和长函数很像,一般也会这样规定,比如参数不能超过5个,道理是一样的,太多的参数不利于代码维护,还容易出错,别人在阅读的时候也不容易理解。
很简单的例子
@Data
@Builder
class Order {
private String orderId;
private BigDecimal amount;
private String orderChannel;
}
@Data
@Builder
class User {
private String userName;
private String userId;
private String userAccount;
private String phone;
private String address;
}
长参数列表方法
public static void longParam(String userName,
String userId,
String userAccount,
String phone,
String address) {
User user = new User();
user.setUserName(userName);
user.setUserId(userId);
user.setUserAccount(userAccount);
user.setPhone(phone);
user.setAddress(address);
// ...
}
可以封装成对象使用
public static void longParam(User user) {
// ...
}
混合类型的长参数列表
public static void longParam(String userAccount,
String userName,
String orderId,
BigDecimal amount,
String orderChannel) {
}
封装成一个混合类型的对象
@Data
class RequestParam{
private String userAccount;
private String userName;
private String orderId;
private BigDecimal amount;
private String orderChannel;
}
使用时再一个个取出来
public static void longParam(RequestParam requestParam){
User user = new User();
user.setUserAccount(requestParam.getUserAccount());
user.setUserName(requestParam.getUserName());
Order order = new Order();
order.setOrderId(requestParam.getOrderId());
order.setOrderChannel(requestParam.getOrderChannel());
order.setAmount(requestParam.getAmount());
}
如果感觉别扭,当然可以进行优化,比如像下面这样:
给RequestParam分别封装一个构建Order和User对象的方法。
@Data
class RequestParam {
private String userAccount;
private String userName;
private String orderId;
private BigDecimal amount;
private String orderChannel;
public Order newOrder() {
return Order.builder()
.amount(amount)
.orderChannel(orderChannel)
.orderId(orderId)
.build();
}
public User newUser() {
return User.builder()
.userAccount(userAccount)
.userName(userName)
.build();
}
}
再使用时就可以像这样
public static void longParam(RequestParam requestParam){
User user = requestParam.newUser();
Order order = requestParam.newOrder();
}
将多个参数封装成对象的方式还有个非常重要的原因就是可以有效的提升方法的兼容性,在方法作为接口对外暴露时,一旦添加或者删除了新的参数,如果没有封装成对象,那么调用者是一定要改的,但如果封装成了一个对象,那么老的远程调用者就很有可能不需要做任何修改。