嵌套代码解决方案
导致嵌套层次过深的原因主要有两点:一是不恰当的嵌套,二是逻辑过于复杂。针对这两种情况,可以分别采用提前返回和封装的手法处理。
1 提前返回
一些代码在使用逻辑判断、循环和异常捕获时,嵌套层次不合理,导致嵌套层次过深。这种情况通常表现为,某个分支中的代码非常简短。这时可以采用提前返回的方式,压缩嵌套层级。
Listing 1: 嵌套不合理
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;
}
}
Listing 2: 提前返回
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)模式:
Listing 3: 嵌套不合理
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;
}
Listing 4: 提前返回 do-while(0)
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;
2 封装
除了嵌套不合理外,逻辑复杂也是导致嵌套层次过深的主要原因。对于这种情况可以采用封装的方法处理。有一些复杂的业务场景,如果过多的使用v-if或者v-for,则会产生大量的嵌套代码,时间拉长后,会让别人难于阅读。如果嵌套代码太多时,有想让代码看起来干净些,我一般的做法是吧代码抽取出来,封装成一个新的组件。那么怎么去抽取呢,一般是吧v-for和 v-if里面的代码都变成一个小组件。Listing 5: 逻辑复杂
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;
Listing 6: 封装
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);
采用封装的方法,总的代码行数会增加。但是每个模块(类、方法)的内聚更高,可复用性更好,客户端代码的编写变得更简单。