http://tommwq.tech/blog/2020/11/09/192
嵌套层次过深会导致代码难以理解和修改,也容易出现逻辑分支缺失,引入缺陷。导致嵌套层次过深的原因主要有两点:一是不恰当的嵌套,二是逻辑过于复杂。针对这两种情况,可以分别采用提前返回和封装的手法处理。
一些代码在使用逻辑判断、循环和异常捕获时,嵌套层次不合理,导致嵌套层次过深。这种情况通常表现为,某个分支中的代码非常简短。这时可以采用提前返回的方式,压缩嵌套层级。
Listing 1: 嵌套不合理
public static Error checkError(List> result) { Error error = new Error(); if (result.size() > 0) { Iterator
Listing 2: 提前返回
public static Error checkSmsError(List> result) { Error error = new Error(); if (result.isEmpty()) { error.setCode(Error.NET_WORK_ERR.errorCode); error.setMessage("ERROR 1"); return error; } Iterator
提前返回还有一种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;
除了嵌套不合理外,逻辑复杂也是导致嵌套层次过深的主要原因。对于这种情况可以采用封装的方法处理。
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);
采用封装的方法,总的代码行数会增加。但是每个模块(类、方法)的内聚更高,可复用性更好,客户端代码的编写变得更简单。