首页 > 解决方案 > 使用重载的方法重复

问题描述

我如何重构“方法”以便不重复代码?对于暂停、恢复和停止,它基本上做同样的事情。目前我正在使用布尔重载的方法,所以不是最好的主意。我不知道要搜索什么,所以给我一些提示

private static void method(final boolean pause, final boolean resume, final boolean stop) {
    planes.forEach(plane -> {
        if (pause) {
            if (plane.getPlaneMovementAnimation() != null) {
                plane.getPlaneMovementAnimation().pause();
            }
            if (plane.getLandingAnimation() != null) {
                plane.getLandingAnimation().pause();
            }
            if (plane.getRandomTransition() != null) {
                plane.getRandomTransition().pause();
            }
        } else if (resume) {
            if (plane.getPlaneMovementAnimation() != null && plane.getStatusMovementAnimation().equals("PAUSED")) {
                plane.getPlaneMovementAnimation().play();
            }
            if (plane.getLandingAnimation() != null && plane.getStatusMovementAnimation().equals("PAUSED")) {
                plane.getLandingAnimation().play();
            }
            if (plane.getRandomTransition() != null && plane.getStatusMovementAnimation().equals("PAUSED")) {
                plane.getRandomTransition().play();
            }
        } else if (stop) {
            if (plane.getPlaneMovementAnimation() != null) {
                plane.getPlaneMovementAnimation().stop();
            }
            if (plane.getLandingAnimation() != null) {
                plane.getLandingAnimation().stop();
            }
            if (plane.getRandomTransition() != null) {
                plane.getRandomTransition().stop();
            }
        }
    });
}

public static void pause() {
    method(true, false, false);
}

public static void resume() {
    method(false, true, false);
}

public static void stop() {
    method(false, false, true);
}

标签: java

解决方案


我认为使用每个命令在其自己的单独方法中的逻辑,这将更具可读性。现在的编写方式,方法中的所有内容都命名为method,使得更难理解每个命令的逻辑,同时没有删除太多重复(仅planes.foreach部分)。也可以以没有意义的方式调用它,例如传递多个true参数。因此,作为多步骤重构过程的第一步,我会将逻辑提取回各个方法中:

public static void pause() {
    planes.forEach(plane -> {
        if (plane.getPlaneMovementAnimation() != null) {
            plane.getPlaneMovementAnimation().pause();
        }
        if (plane.getLandingAnimation() != null) {
            plane.getLandingAnimation().pause();
        }
        if (plane.getRandomTransition() != null) {
            plane.getRandomTransition().pause();
        }
    });
}

public static void resume() {
    planes.forEach(plane -> {
        if (plane.getPlaneMovementAnimation() != null && plane.getStatusMovementAnimation().equals("PAUSED")) {
            plane.getPlaneMovementAnimation().play();
        }
        if (plane.getLandingAnimation() != null && plane.getStatusMovementAnimation().equals("PAUSED")) {
            plane.getLandingAnimation().play();
        }
        if (plane.getRandomTransition() != null && plane.getStatusMovementAnimation().equals("PAUSED")) {
            plane.getRandomTransition().play();
        }
    });
}

public static void stop() {
    planes.forEach(plane -> {
        if (plane.getPlaneMovementAnimation() != null) {
            plane.getPlaneMovementAnimation().stop();
        }
        if (plane.getLandingAnimation() != null) {
            plane.getLandingAnimation().stop();
        }
        if (plane.getRandomTransition() != null) {
            plane.getRandomTransition().stop();
        }
    });
}

接下来,如果Plane能够更改类,我将在该类中封装每个命令的逻辑。这样,调用者就不需要知道飞机每个动画的内部细节:

public static void pause() {
    planes.forEach(Plane::pause);
}

public static void resume() {
    planes.forEach(Plane::resume);
}

public static void stop() {
    planes.forEach(Plane::stop);
}

class Plane {
    public void pause() {
        if (getPlaneMovementAnimation() != null) {
            getPlaneMovementAnimation().pause();
        }
        if (getLandingAnimation() != null) {
            getLandingAnimation().pause();
        }
        if (getRandomTransition() != null) {
            getRandomTransition().pause();
        }

    }

    public void resume() {
        if (getPlaneMovementAnimation() != null && getStatusMovementAnimation().equals("PAUSED")) {
            getPlaneMovementAnimation().play();
        }
        if (getLandingAnimation() != null && getStatusMovementAnimation().equals("PAUSED")) {
            getLandingAnimation().play();
        }
        if (getRandomTransition() != null && getStatusMovementAnimation().equals("PAUSED")) {
            getRandomTransition().play();
        }
    }

    public void stop() {
        if (getPlaneMovementAnimation() != null) {
            getPlaneMovementAnimation().stop();
        }
        if (getLandingAnimation() != null) {
            getLandingAnimation().stop();
        }
        if (getRandomTransition() != null) {
            getRandomTransition().stop();
        }
    }

    // ...
}

如果您不熟悉语法,Plane::pause其他类似的语法是 lambda 表达式的快捷方式,称为方法引用Plane::pause与 相同plane -> plane.pause()

当然,这只会将重复项移入Plane,所以让我们继续。该方法的结构与其他resume方法略有不同,因为它检查getStatusMovementAnimation().equals("PAUSED")每个if语句。我们可以将该检查提取到外部if,因为每个检查都是相同的:

    public void resume() {
        if (getStatusMovementAnimation().equals("PAUSED")) {
            if (getPlaneMovementAnimation() != null) {
                getPlaneMovementAnimation().play();
            }
            if (getLandingAnimation() != null) {
                getLandingAnimation().play();
            }
            if (getRandomTransition() != null) {
                getRandomTransition().play();
            }
        }
    }

现在每种方法的结构几乎相同。假设getPlaneMovementAnimation()getLandingAnimation()getRandomTransition()都返回相同的类型(我称之为Animation),我们可以提取一个方法,该方法返回null飞机的非动画集合:

class Plane {
    private Collection<Animation> getActiveAnimations() {
        Collection<Animation> activeAnimations = new HashSet<>();
        if (getPlaneMovementAnimation() != null) {
            activeAnimations.add(getPlaneMovementAnimation());
        }
        if (getLandingAnimation() != null) {
            activeAnimations.add(getLandingAnimation());
        }
        if (getRandomTransition() != null) {
            activeAnimations.add(getRandomTransition());
        }
        return Collections.unmodifiableCollection(activeAnimations);
    }

    public void pause() {
        getActiveAnimations().forEach(Animation::pause);
    }

    public void resume() {
        if (getStatusMovementAnimation().equals("PAUSED")) {
            getActiveAnimations().forEach(Animation::play);
        }
    }

    public void stop() {
        getActiveAnimations().forEach(Animation::stop);
    }

现在,几乎没有任何重复。只有getActiveAnimations().forEachandplanes.forEach调用。就个人而言,我认为不值得尝试删除这种重复,因为它只是每个地方的一个电话。但是,如果你真的想要,你可以提取forEachPlaneforEachAnimation这样的方法:

private static void forEachPlane(Consumer<Plane> action) {
    planes.forEach(action);
}

推荐阅读