架构师书房-《代码不朽》-深层嵌套条件语句的简化

大家好,我是码农老吴,欢迎收看架构师书房。上期,我们聊了如何简化switch语句,本期,我们看看如何简化深层嵌套的条件语句(deeply nested conditional)。

架构师书房-《代码不朽》-深层嵌套条件语句的简化

案例-深层嵌套的条件语句

优化前

BinaryTreeNode:二分查找树节点(binary search tree node)。

package eu.sig.training.ch03.binarytree;

public class BinaryTreeNode> {
    private final T value;
    private BinaryTreeNode left;
    private BinaryTreeNode right;

    public BinaryTreeNode(T value) {
        this.value = value;
    }

    public void insert(T value) {
        if (value.compareTo(this.value) < 0) {
            if (left != null) {
                left.insert(value);
            } else {
                left = new BinaryTreeNode(value);
            }
        } else {
            if (right != null) {
                right.insert(value);
            } else {
                right = new BinaryTreeNode(value);
            }
        }
    }

    public BinaryTreeNode getLeft() {
        return left;
    }

    public BinaryTreeNode getRight() {
        return right;
    }

    public T getValue() {
        return value;
    }

    public boolean isLeaf() {
        return left == null && right == null;
    }
}
package eu.sig.training.ch03.binarytree;

@SuppressWarnings("serial")
public class TreeException extends RuntimeException {
    public TreeException(String msg) {
        super(msg);
    }
}

BinaryTreeSearch.calculateDepth():计算二分查找树的深度

点评:

以下代码calculateDepth方法,if else 有三层嵌套。

package eu.sig.training.ch03.binarytree.v1;

import eu.sig.training.ch03.binarytree.TreeException;
import eu.sig.training.ch03.binarytree.BinaryTreeNode;

public class BinaryTreeSearch {

    // tag::calculateDepth[]
    public static int calculateDepth(BinaryTreeNode t, int n) {
        int depth = 0;
        if (t.getValue() == n) {
            return depth;
        } else {
            if (n < t.getValue()) {
                BinaryTreeNode left = t.getLeft();
                if (left == null) {
                    throw new TreeException("Value not found in tree!");
                } else {
                    return 1 + calculateDepth(left, n);
                }
            } else {
                BinaryTreeNode right = t.getRight();
                if (right == null) {
                    throw new TreeException("Value not found in tree!");
                } else {
                    return 1 + calculateDepth(right, n);
                }
            }
        }
    }
    // end::calculateDepth[]
}

第一次优化-使用卫语句代替嵌套的条件语句

(Replace nested conditional with Guard clauses pattern)

Guard clauses pattern

A guard clause is a software pattern that simplifies complex functions by “failing fast”, checking for invalid inputs up front and immediately failing if any are found.

卫语句是一种通过快速失败来简化复杂代码的软件开发模式,也是我经常使用的一种编写习惯,它常常用来简化代码嵌套的层级。这种模式的一个显著特点就是对return语句的高频使用,当然还有其他方式,大家如果感兴趣,评论区请留言,我可以做个专题分享。

package eu.sig.training.ch03.binarytree.v2;

import eu.sig.training.ch03.binarytree.BinaryTreeNode;
import eu.sig.training.ch03.binarytree.TreeException;

public class BinaryTreeSearch {

    // tag::calculateDepth[]
    public static int calculateDepth(BinaryTreeNode t, int n) {
        int depth = 0;
        if (t.getValue() == n)
            return depth;
        if (n < t.getValue() && t.getLeft() != null)
            return 1 + calculateDepth(t.getLeft(), n);
        if (n > t.getValue() && t.getRight() != null)
            return 1 + calculateDepth(t.getRight(), n);
        throw new TreeException("Value not found in tree!");
    }
    // end::calculateDepth[]

}

点评

calculateDepth方法,经过卫语句简化之后,由原来的三层嵌套,变成了一层嵌套。

这段代码其实已经很好了,美中不足的是分支点还是有些多,大家数数有几个分支点,肯定超过4个了,作者又换了另外一种方式进行优化。

第二次优化-提取方法,继续简化代码

package eu.sig.training.ch03.binarytree.v3;

import eu.sig.training.ch03.binarytree.BinaryTreeNode;
import eu.sig.training.ch03.binarytree.TreeException;

public class BinaryTreeSearch {

    // tag::calculateDepth[]
    public static int calculateDepth(BinaryTreeNode t, int n) {
        int depth = 0;
        if (t.getValue() == n)
            return depth;
        else
            return traverseByValue(t, n);
    }

    private static int traverseByValue(BinaryTreeNode t, int n) {
        BinaryTreeNode childNode = getChildNode(t, n);
        if (childNode == null) {
            throw new TreeException("Value not found in tree!");
        } else {
            return 1 + calculateDepth(childNode, n);
        }
    }

    private static BinaryTreeNode getChildNode(
        BinaryTreeNode t, int n) {
        if (n < t.getValue()) {
            return t.getLeft();
        } else {
            return t.getRight();
        }
    }
    // end::calculateDepth[]

}

点评

上面的代码,将一个方法,提取成了三个方法。每个方法,逻辑都很简单,分支点都不超过4个,但是代码总量增加了不少。至于是否采用,大家见仁见智,根据自己的实际情况决定。

反思

从上面大家是否可以体悟到一个事实,简化代码并等于减少代码,简化代码单元里面的代码,并不意味着减少代码的总量。

程序员和建筑工人不同,程序员为了简单,为了美观,可以输入更多的代码,因为这些不需要成本,而建筑工人,就不能这么随意了,每一块砖,每一片瓦,每一根木头,都是会增加项目成本的。所以,程序员应该感到幸福。

本期我们就聊到这里,下期,我们开始聊第三个原则,不写重复的代码(Write code once)。

极客架构师,专注架构师成长,我们下期见。

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章