编程和齐物程序员的修炼之路

简洁代码之道(1):用多态替代条件语句

2018-12-28  本文已影响0人  Yonah潇

前言

本文是我看了 谷歌简洁代码演讲系列 中的 多态和条件语句 的总结。大部分的条件语句是可以用多态代替的,本文将围绕以下问题开展:

为什么要用多态替代条件语句

多态和条件语句的使用场景

使用多态的场景

使用条件语句的场景

这篇文章主要着重于如何避免 if 语句。

如何避免使用 if 语句

如何用多态代替条件语句

如果你有一个条件语句,它根据对象的类型选择不同的行为。那么如何用多态来替代它呢?下面,我们来看一个例子。

条件语句实现的类

Class Update {
    execute() {
        if (FLAG_i18n_ENABLE) {
            //DO A;
        } else {
            //DO B;
        }
    }
    render() {
        if (FLAG_i18n_ENABLE) {
            //render A;
        } else {
            //render B;
        }
    }
}

上面的类根据 FLAG_i18n_ENABLE 来执行不同的操作。可能你以前就是这么写代码的,觉得这样写一点问题都没有。那么,我现在问你,怎么测试上面的类?

下面我们来看看一般的测试方法。

void testExecuteDoA() {
    FLAG_i18n_ENABLE = true;
    Update u = new Update();
    u.execute();
    assertX();
}
void testExecuteDoB() {
    FLAG_i18n_ENABLE = false;
    Update u = new Update();
    u.execute();
    assertX();
}

看完上面的代码,你可能也觉得似曾相识,也觉得没什么问题。

实际上,这样写的类有以下几个问题:

多态实现的类

那么,如何用多态来重写上面的类呢?

我们可以分为两步来操作:

代码如下

abstract class Update {
    abstract execute();
    abstract render();
}

class I18NUpdate extends Update {
    execute() {
        //Do A;
    }
    render() {
        //render A;
    }
}

class NonI18NUpdate extends Update {
    execute() {
        //Do B;
    }
    render() {
        //render B;
    }
}

测试方法:

void testExecuteDoA() {
    Update u = new I18NUpdate();
    u.execute();
    assertX();
}
void testExecuteDoB() {
    Update u = new NonI18NUpdate();
    u.execute();
    assertX();
}

用多态实现的类,通过继承抽象类,重写抽象方法的方式,避免使用了条件语句。在测试的时候,不需要关心它的状态码,子类本身就已经承载了状态信息。所以你可以看到,在测试的时候,代码非常的清晰易懂。

总结

使用多态实现的类有两个好处:

在哪里决定要创建什么子类

咋一看上面的标题有点绕,我们来详细讨论一下问题的来源。上面我们讲了如何多态代替条件语句,但是有一个问题是无法回避的:我们怎么判断要创建哪一种子类?

实际上,我们还是要依靠 FLAG_i18n_ENABLE 来决定实例化哪个子类,也就是说,我们仍然要用到条件语句。看到这里你可能就觉得:说到底还是要靠条件语句,博主忽悠人。此言差矣,这么说,条件语句的使用是必要不充分的。写程序你肯定要用到条件语句,但是用的太多会有前面我们说到的问题。把多态和条件语句结合,才是正道。

我们回到前面的问题,既然条件语句无法避免,因为我们要根据条件决定使用哪个子类。我们先来对类做一个粗略的划分。

通过上面的划分,我们可以把子类创建交给工厂类。

class Consumer {
    Cosumer(Update u) {...}
}

class Factory {
    Consumer build() {
        Update u = FLAG_i18n_ENABLE
                    ? new I18NUpdate()
                    : new NonI18NUpdate;
        return new Consumer(u);
    }
}

现在我们可以回答上面的问题了:在工厂类中根据条件决定要创建哪个子类。这样处理有以下的好处:

什么情况下使用多态

多态虽好,可不要滥用。 – Yonah潇

最后,我只说一句:该用条件语句的时候不要强行用多态。

参考资料
多态和条件语句

上一篇下一篇

猜你喜欢

热点阅读