前言
在CR代码的过程中,发现很多人的代码都存在很多问题,和同事讨论思考了下,可能是因为他并不知道如何更好的组织。其实写代码这件事有很多方法论,这篇文章主要就是告诉你,如何使用方法论写出更好的代码。这篇文章将展示一些糟糕的代码,以及如何让他们变得优雅。
烦人的if
程序流程由顺序、分支、循环构成,if是代码中不可或缺的部分。
卫语句
/**
* 获取列表中早于今天的所有日期
*
* @param list 待筛选列表
* @return 早于今天的所有日期列表
*/
public List<Date> getDaysBeforeNow(List<String> list) {
Date now = new Date();
List<Date> dates = Lists.newArrayList();
for (String str : list) {
if (StringUtils.isNotEmpty(str)) {
Date date = DateUtil.parse(str, DateUtil.yyyyMMddHHmmssWithSpliter);
if (date.before(now)) {
dates.add(date);
}
}
}
return dates;
}
这是一个简单的功能,但是他的层级嵌套了三层之多。那么使用卫语句之后呢
/**
* 获取列表中早于今天的所有日期
*
* @param list 待筛选列表
* @return 早于今天的所有日期列表
*/
public List<Date> getDaysBeforeNow(List<String> list) {
Date now = new Date();
List<Date> dates = Lists.newArrayList();
for (String str : list) {
if (StringUtils.isEmpty(str)) {
continue;
}
Date date = DateUtil.parse(str, DateUtil.yyyyMMddHHmmssWithSpliter);
if (date.before(now)) {
dates.add(date);
}
}
return dates;
}
使用Map替代if
/**
* 你晚饭想吃什么,我都做给你 :)
* @param cook 你想吃什么呢
*/
public void whatYouWant(CookType cook) {
if (cook == CookType.RICE) {
new CookRice().cook();
} else if (cook == CookType.CONGEE) {
new CookCongee().cook();
} else if (cook == CookType.NOODLES) {
new CookNoodles().cook();
} else {
throw new UnsupportedOperationException("做不了,另请高明");
}
}
辅助类定义
enum CookType {
RICE, NOODLES, CONGEE;
}
interface Cook {
void cook();
}
class CookRice implements Cook {
@Override
public void cook() {
//煮米饭
}
}
class CookNoodles implements Cook {
@Override
public void cook() {
//煮面条
}
}
class CookCongee implements Cook {
@Override
public void cook() {
//煮粥
}
}
在上面的case中,多个if分支拼在一起,代码可读性就差很多,那么用Map怎么做呢
private Map<CookType, Cook> cookMap = Maps.newHashMap();
{
cookMap.put(CookType.RICE, new CookRice());
cookMap.put(CookType.NOODLES, new CookNoodles());
cookMap.put(CookType.CONGEE, new CookCongee());
}
/**
* 你晚饭想吃什么,我都做给你 :)
*
* @param cook 你想吃什么呢
*/
public void whatYouWant(CookType cook) {
if (!cookMap.containsKey(cook)) {
throw new UnsupportedOperationException("做不了,另请高明");
}
cookMap.get(cook).cook();
}
使用Predicate替代if
经常会碰到多个if嵌套的情况,如果这个订单至少包含三件物品,并且总价在300以上,没有使用优惠券的情况,那么可以享受包邮。
class Order {
List<Good> goodList;
boolean isUseBonus;
BigDecimal price;
//get/set
}
class Good {
}
//是否需要支付邮费
private static boolean checkIfNeedExpressBee(Order order) {
//使用优惠券
if (order.isUseBonus) {
return true;
}
//总价大于300
if (order.price.subtract(new BigDecimal(300)).doubleValue() < 0) {
return true;
}
//至少包含三件
return CollectionUtils.size(order.goodList) < 3;
}
Predicate版本(Guava)
private static boolean checkIfNeedExpressBee(Order order) {
return CHECK_IS_NEED_EXPRESS_BEE.apply(order);
}
private static final Predicate<Order> CHECK_PRICE = new Predicate<Order>() {
@Override
public boolean apply(Order order) {
return order.price.subtract(new BigDecimal(300)).doubleValue() >= 0;
}
};
private static final Predicate<Order> CHECK_NUMBER = new Predicate<Order>() {
@Override
public boolean apply(Order order) {
return CollectionUtils.size(order.goodList) >= 3;
}
};
private static final Predicate<Order> CHECK_BONUS = new Predicate<Order>() {
@Override
public boolean apply(Order order) {
return CollectionUtils.size(order.goodList) < 3;
}
};
private static final Predicate<Order> CHECK_IS_NEED_EXPRESS_BEE = Predicates.and(CHECK_PRICE, CHECK_NUMBER, CHECK_BONUS);
Lambda+Predicate版
private static boolean checkIfNeedExpressBee(Order order) {
return CHECK_IS_NEED_EXPRESS_BEE.apply(order);
}
private static final Predicate<Order> CHECK_PRICE = order -> order.price.subtract(new BigDecimal(300)).doubleValue() < 0;
private static final Predicate<Order> CHECK_NUMBER = order -> CollectionUtils.size(order.goodList) < 3;
private static final Predicate<Order> CHECK_BONUS = order -> order.isUseBonus;
private static final Predicate<Order> CHECK_IS_NEED_EXPRESS_BEE = Predicates.or(CHECK_PRICE, CHECK_NUMBER, CHECK_BONUS);
从上面示例代码看不出predicate的优势,但是在实际业务中,判断条件更复杂,使用predicate有助于代码逻辑的整理,使其解耦,高内聚。
–持续更新
欢迎加群,一起学习进步