嵌套代码解决方案

导致嵌套层次过深的原因主要有两点:一是不恰当的嵌套,二是逻辑过于复杂。针对这两种情况,可以分别采用提前返回和封装的手法处理。

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);
采用封装的方法,总的代码行数会增加。但是每个模块(类、方法)的内聚更高,可复用性更好,客户端代码的编写变得更简单。

posted @ 2022-11-04 09:29  2723947616蕶  阅读(108)  评论(0编辑  收藏  举报