有哪些技巧可以用来尽可能减少代码中的if/else嵌套?

如题。代码中嵌套的if/else结构往往导致代码不美观,也不易于理解,那么有哪些技巧可以用来尽可能减少代码中的if/else嵌套呢?

阅读 22k
11 个回答

尽量少使用 else,如果在函数中,可以使用 if + return,先判断错误条件,然后立马结束函数,防止进入 else 分支。

刚才去 sof 溜了一圈,发现也有人在问:How to avoid if… else and switch cases


解决方法:

1. switch/case

不解释。

2. hash 表

if (key == "Apple") {
    val = "Jobs";
} else if (key == "microsoft"){
    val = "Gates";
} else if (key == "Google"){
    val = "Larry";
} 

这个也可以用 switch case 解决,不过推荐的方法是 hash 表:

var ceos = {"Apple":"Jobs", "microsoft":"Gates", "Google":"Larry"};
val = ceos[key];

3. 重构,用 OO 里面的继承或者组合

  1. 如果是狗,则汪汪
  2. 如果是猫,则喵喵
  3. 如果是羊,则咩咩
  4. 如果是鸡,则呀咩碟

可以重构一下,改成 OO。

  • 定义类:动物(或者接口)
  • 定义方法:叫
  • 定义子类:狗、猫、羊、鸡
  • 重写方法——叫。

说一个实际问题:redis能够处理很多的个命令(譬如,get, set,lpush等等),如果你用if,else写(伪代码):

    def process(cmd_name, args)
        if cmd_name == "get":
            # do_action
        else if cmd_name == "set":
            # do_action
        else if ...

很显然这样子写很显然效率低下,而且毎扩展一个命令效率就更加慢,那redis是怎么处理的呢?利用哈希表(伪代码):

redisCommand = [
    # 命令名, 命令处理函数
    ("get", getCommand),
    {"set", setCommand)
    # ...
] 

然后初始化哈希表:dictCmd,其中:
    dictCmd.key -> 命令名
    dictCmd.val -> 命令处理函数

这个时候处理命令函数变成:
    def process(cmd_name, args):
        proc = dictCmd.get(cmd_name)
        proc(args)

这样就解决了效率问题,扩展一个新命令也非常容易

这其实只是遇到多重if问题的一种解决方法(而且只适合特定场景),有的系统业务复杂,你很难有什么好的方法, 但至少保证代码写的整洁,可读性强

我会用

do {
...
}while(false);

例如

do {
if( test == 1 ) {
    break;
}
}
//do anything else ...
  1. 使用switch
  2. 把不同的判断按照功能,写成函数,这样也便于阅读

……为了解决这个复杂嵌套的问题,原始程序员们设计了switch这个函数。。so……

学学策略模式,我最常用的就是用map

还是得看具体情况吧,如果比较简单的判断得到结果确实可以考虑Hash,但是如果是比较复杂的业务逻辑的话也不是Hash可以解决的,所以还是要结合具体情况,也推荐多看些设计模式方面的东西。

https://pypi.python.org/pypi/singledispatch

平时一般用 getattr 写个简单的 dispatch

if a == 'b':
    print('a=b')
if c == 'd':
    print('c=d')

class dispatch():

    def error(self):
        print('error')

    def __init__(self, func=''):
        getattr(self, func, self.error)

    def a(self):
        print('a=b')

    def c(self):
        print('c=d')

dispatch('a')
dispatch('b')

对于if中的异常情况,在java中可以用PreConditions包,好像是google的一个包,用法就是:

PreConditions.checkArgument(var, errMsg);

就是说那个变量如果是false就会抛InvalidArgument 异常。
那个包里面提供了非常多的判断各种异常值的静态方法。使用这些方法可以大大的减少分支。(在我们公司,就对代码复杂度有要求,它会作为项目结果的一部分,如果不达标,项目结果就会受影响。)

当然,也不是所有的时候都要抛异常,有时候要对一些情况做一些处理,或者是,程序本身就会有分支,像这种情况,就需要在设计接口、api的时候就充分考虑:
有一些流程的分支,使用多态的方式,由不同的类处理。
有一些业务上相关的数据问题,可以使用自定义的异常,并且在调用的地方进行处理。
如果是同样类型的判断很多地方都要做,那就抽取出来,写一个判断的函数。

最后,还有一点就是,尽量的使用基于协议的方式去编程,不该出现的异常情况,在源头就抛出去,其他地方就不需要再考虑这种情况。

使用多态解决

##### 定义一个接口
interface Operation {
    void execute();
}

##### 实现具体的操作类
class OperationA implements Operation {
    @Override
    public void execute() {
        // 实现操作 A 的逻辑
    }
}

class OperationB implements Operation {
    @Override
    public void execute() {
        // 实现操作 B 的逻辑
    }
}

##### 在调用处使用多态
Operation operation;
if (conditionA) {
    operation = new OperationA();
} else if (conditionB) {
    operation = new OperationB();
}
operation.execute();
宣传栏