如何避免代码多层嵌套

Catalogue
  1. 1. if作用
  2. 2. if用于参数合法性校验
    1. 2.1. 使用break,continue
    2. 2.2. 使用异常
  3. 3. if用于控制业务流程
    1. 3.1. 使用多态
    2. 3.2. 使用枚举
    3. 3.3. 使用map
    4. 3.4. 抽取方法
    5. 3.5. 参考

平时写代码过程中,过多if判断语句的存在导致代码产生多层嵌套,影响代码可读性。

if作用

代码中if主要用于控制代码流程:

  1. 参数合法性校验
  2. 业务流程走向

if用于参数合法性校验

当if用于参数合法性校验时,避免多层嵌套,可采用以下方式:

使用break,continue

有些人写代码,习惯通过if(condition){}判真的方式控制流程走向,这种方式会造成代码多层嵌套。
如果我们反过来,采用if(!condition){return; break; continue}判假的方式提前退出嵌套则可减少代码嵌套。进入方法,参数不合法,提前return;进入循环,不满足则break退出循环或continue进行快速进入下一次循环。

使用异常

一般情况下,我们使用if主要是为了参数校验,一次又一次的if判断,导致多层嵌套的出现,但又不能不做,很是尴尬。

这种情况,可考虑使用异常统一捕获,try代码块中不做参数校验,所有NPE异常交由外层catch。
当然,使用try..catch,一旦异常触发,可能会降低程序的性能;如果做参数检验仅仅是为了避免极端情况的崩溃,在大部分情况下不会发生异常,那么可以放心使用。

if用于控制业务流程

使用多态

比如以下代码:根据type调用不同通知接口给用户发送通知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void sendNotify(Integer type, String msg) {
if (type == 1) {
sendEmail(msg);
} else if (type == 2){
sendMsg(msg);
} else if (type == 3){
sendWechat(msg);
}
}
private void sendWechat(String msg) {
System.out.println("wechat" + msg);
}
private void sendMsg(String msg) {
System.out.println("message" + msg);
}
private void sendEmail(String msg) {
System.out.println("email" + msg);
}

多态解决:
抽象出一个基类

1
2
3
4
5
6
7
8
9
10
11
public abstract class SendNotify {
public void send(String msg) {
System.out.println("start send");
doSend(msg);
System.out.println("end send");
}
public abstract void doSend(String msg);
}

子类继承父类,同时自己实现具体的发送通知操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class SendEmial extends SendNotify {
@Override
public void doSend(String msg) {
System.out.println("email" + msg);
}
}
public class SendMsg extends SendNotify {
@Override
public void doSend(String msg) {
System.out.println("message" + msg);
}
}
public class SendWechat extends SendNotify {
@Override
public void doSend(String msg) {
System.out.println("wechat" + msg);
}
}

测试:

1
2
3
4
5
6
7
8
9
10
11
public void testSendNotify() {
//采用双括号初始化赋值
Map<Integer, SendNotify> sendNotifyMap = new HashMap() {{
put(1, new SendEmial());
put(2, new SendMsg());
put(3, new SendWechat());
}} ;
SendNotify sendNotify = sendNotifyMap.get(2);
sendNotify.send("hello");
}

使用枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public enum NotifyEnum {
Emial(1, SendEmial.class), Msg(2, SendMsg.class), Wechat(3, SendWechat.class);
private Integer type;
private Class clazz;
NotifyEnum(int type, Class clazz) {
this.type = type;
this.clazz = clazz;
}
public static NotifyEnum find(int type) {
for (NotifyEnum notify : values()) {
if (notify.type == type) {
return notify;
}
}
return null;
}
public Integer getType() {
return type;
}
public Class getClazz() {
return clazz;
}
}

测试:

1
2
3
4
5
public void testEnumSendNotify() throws IllegalAccessException, InstantiationException {
NotifyEnum notifyEnum = NotifyEnum.find(3);
SendNotify notify = (SendNotify)notifyEnum.getClazz().newInstance();
notify.send("world");
}

使用map

通过K-V的方式存入map,调用时不用if判断,跟枚举类似。

1
2
3
4
5
6
7
8
9
public void testSendNotify() {
Map<Integer, SendNotify> sendNotifyMap = new HashMap() ;
sendNotifyMap.put(1, new SendEmial());
sendNotifyMap.put(2, new SendMsg());
sendNotifyMap.put(3, new SendWechat());
SendNotify sendNotify = sendNotifyMap.get(2);
sendNotify.send("hello");
}

抽取方法

通过抽取方法可将多层多层嵌套分配到各个方法中去,减少主方法的嵌套层数,提高可读性。

参考

编写优美的代码之减少嵌套

Comments