降低代码嵌套层数的两种方法
·
[tommwq@126.com]
嵌套层次过深会导致代码难以理解和修改,也容易出现逻辑分支缺失,引入缺陷。导致嵌套层次过深的原因主要有两点:一是不恰当的嵌套,二是逻辑过于复杂。针对这两种情况,可以分别采用提前返回和封装的手法处理。
提前返回
一些代码在使用逻辑判断、循环和异常捕获时,嵌套层次不合理,导致嵌套层次过深。这种情况通常表现为,某个分支中的代码非常简短。这时可以采用提前返回的方式,压缩嵌套层级。
public static Error checkError(List<DataTable<String, String>> result) {
Error error = new Error();
if (result.size() > 0) {
Iterator<Map<String, String>> it = result.get(0).iterator();
if (it.hasNext()) {
Map<String, String> e = it.next();
if (e.containsKey("code")) {
String code = e.get("code");
if ("0".equals(code)) {
return null;
} else {
error.setCode(Integer.parseInt(code.replace("0x", ""), 16));
error.setMessage(e.get("message"));
return error;
}
} else {
error.setCode(Error.NET_WORK_ERR.errorCode);
error.setMessage("ERROR 1");
return error;
}
} else {
error.setCode(Error.NET_WORK_ERR.errorCode);
error.setMessage("ERROR 2");
return error;
}
} else {
error.setCode(Error.NET_WORK_ERR.errorCode);
error.setMessage("ERROR 3");
return error;
}
}
public static Error checkSmsError(List<DataTable<String, String>> result) {
Error error = new Error();
if (result.isEmpty()) {
error.setCode(Error.NET_WORK_ERR.errorCode);
error.setMessage("ERROR 1");
return error;
}
Iterator<Map<String, String>> it = result.get(0).iterator();
if (!it.hasNext()) {
error.setCode(Error.NET_WORK_ERR.errorCode);
error.setMessage("ERROR 2");
return error;
}
Map<String, String> e = it.next();
if (!e.containsKey("code")) {
error.setCode(Error.NET_WORK_ERR.errorCode);
error.setMessage("ERROR 3");
return error;
}
String code = e.get("code");
if ("0".equals(code)) {
return null;
}
String message = e.getOrDefault("message", "");
if (HelperUtil.shouldPreventSmsError(code, message)) {
return null;
}
error.setCode(Integer.parseInt(code.replace("0x", ""), 16));
error.setMessage(message);
return error;
}
提前返回还有一种do-while(0)模式:
FILE *f1 = fopen("a.txt", "r");
if (f1 != NULL) {
FILE *f2 = fopen("b.txt", "r");
if (f2 != NULL) {
FILE *f3 = fopen("b.txt", "r");
if (f3 != NULL) {
int result = do_something(f1, f2, f3);
fclose(f1);
fclose(f2);
fclose(f3);
return result;
} else {
fclose(f1);
fclose(f2);
return -1;
}
} else {
fclose(f1);
return -1;
}
} else {
return -1;
}
int result = 0;
FILE *f1 = NULL;
FILE *f2 = NULL;
FILE *f3 = NULL;
do {
FILE *f1 = fopen("a.txt", "r");
if (f1 == NULL) {
break;
}
FILE *f2 = fopen("b.txt", "r");
if (f2 == NULL) {
break;
}
FILE *f3 = fopen("c.txt", "r");
if (f3 == NULL) {
break;
}
result = do_something(f1, f2, f3);
} while (0);
if (f1 != NULL) {
fclose(f1);
}
if (f2 != NULL) {
fclose(f1);
}
if (f3 != NULL) {
fclose(f1);
}
return result;
封装
除了嵌套不合理外,逻辑复杂也是导致嵌套层次过深的主要原因。对于这种情况可以采用封装的方法处理。
double discountRate = 1.0;
int extraDiscount = 0;
if (itemId == Item.FRUIT) {
if (itemCount >= 10) {
discountRate = 0.9;
} else if (itemCount >= 50) {
discountRate = 0.85;
extraDiscount = 10;
} else if (itemCount >= 100) {
discountRate = 0.8;
extraDiscount = 20;
}
} else if (itemId == Item.MILK) {
if (itemCount >= 20) {
discountRate = 0.88;
}
} else {
if (itemCount >= 30) {
discountRate = 0.9;
}
}
double originalPrice = itemCount * itemPrice;
double price = originalPrice * discountRate - extraDiscount;
interface DiscountStrategy {
double getDiscountedPrice(int itemCount, double originalPrice);
}
class NormalDiscountStrategy implements DiscountStrategy {
public double getDiscountedPrice(int itemCount, double originalPrice) {
double rate = 1.0;
if (itemCount > 30) {
rate = 0.9;
}
return originalPrice * rate;
}
}
class MilkDiscountStrategy implements DiscountStrategy {
public double getDiscountedPrice(int itemCount, double originalPrice) {
double rate = 1.0;
if (itemCount > 20) {
rate = 0.88;
}
return originalPrice * rate;
}
}
class FruitDiscountStrategy implements DiscountStrategy {
public double getDiscountedPrice(int itemCount, double originalPrice) {
double rate = 1.0;
int extra = 0;
if (itemCount >= 10) {
rate = 0.9;
} else if (itemCount >= 50) {
rate = 0.85;
extra = 10;
} else if (itemCount >= 100) {
rate = 0.8;
extra = 20;
}
return originalPrice * rate - extra;
}
}
class DiscountStrategyFactory {
DiscountStrategy getDiscountStrategy(int itemId) {
switch (itemId) {
case Item.FRUIT:
return new FruitDiscountStrategy();
case Item.MILK:
return new MilkDiscountStrategy();
default:
return new NormalDiscountStrategy();
}
}
}
double originalPrice = itemCount * itemPrice;
double price = DiscountStrategyFactory.getDiscountStrategy(itemId).getDiscountedPrice(itemCount, originalPrice);
采用封装的方法,总的代码行数会增加。但是每个模块(类、方法)的内聚更高,可复用性更好,客户端代码的编写变得更简单。