两个重载方法,相同的操作,导致重复的代码

时间:2017-12-21 19:28:35

标签: java javafx javafx-8

我有两种方法可以使用CircleScene,并通过每N ms更改fill值使背景闪烁红 - 绿 - 蓝。

这两种方法:

private void makeRGB(Circle c) {
    Timer t = new Timer();
    t.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            if(c.getFill() == Color.RED) {
                c.setFill(Color.GREEN);
            } else if (c.getFill() == Color.GREEN) {
                c.setFill(Color.BLUE);
            } else {
                c.setFill(Color.RED);
            }
        }
    },0, RGB_CHANGE_PERIOD);
}

private void makeRGB(Scene s) {
    Timer t = new Timer();
    t.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            if(s.getFill() == Color.RED) {
                s.setFill(Color.GREEN);
            } else if (s.getFill() == Color.GREEN) {
                s.setFill(Color.BLUE);
            } else {
                s.setFill(Color.RED);
            }
        }
    },0, RGB_CHANGE_PERIOD);
}

显然这些非常相似,但是由于CircleScene不在同一个继承树中,我不能使用调用它们的超类的方法包含{{1} } / .setFill()方法。

我如何在这里删除代码重复?

1 个答案:

答案 0 :(得分:10)

通常,通过将公共代码分解为函数/方法/类并参数化变化的部分来删除重复代码。在这种情况下,您检索当前填充的方式以及设置新填充的方式会有所不同。 java.util.function包提供了适当的参数化类型,因此您可以这样做:

private void makeRGB(Circle c) {
    makeRGB(c::getFill, c:setFill);
}

private void makeRGB(Scene s) {
    makeRGB(s::getFill, s:setFill);
}

private void makeRGB(Supplier<Paint> currentFill, Consumer<Paint> updater) {
    Timer t = new Timer();
    t.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            if(currentFill.get() == Color.RED) {
                updater.accept(Color.GREEN);
            } else if (currentFill.get() == Color.GREEN) {
                updater.accept(Color.BLUE);
            } else {
                updater.accept(Color.RED);
            }
        }
    },0, RGB_CHANGE_PERIOD);
}

但请注意,您不应该从后台线程更改UI。你应该真的这样做

private void makeRGB(Supplier<Paint> currentFill, Consumer<Paint> updater) {
    Timer t = new Timer();
    t.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            Platform.runLater(() -> {
                if(currentFill.get() == Color.RED) {
                    updater.accept(Color.GREEN);
                } else if (currentFill.get() == Color.GREEN) {
                    updater.accept(Color.BLUE);
                } else {
                    updater.accept(Color.RED);
                }
            }
        }
    },0, RGB_CHANGE_PERIOD);
}

或,(更好),use a Timeline定期做事。

如评论中所述,您还可以提供Map,将每种颜色映射到其后的颜色。结合所有这些给出了:

private final Map<Paint, Paint> fills = new HashMap<>();

// ...

    fills.put(Color.RED, Color.GREEN);
    fills.put(Color.GREEN, Color.BLUE);
    fills.put(Color.BLUE, Color.RED);

// ...

private void makeRGB(Circle c) {
    makeRGB(c::getFill, c:setFill);
}

private void makeRGB(Scene s) {
    makeRGB(s::getFill, s:setFill);
}

private void makeRGB(Supplier<Paint> currentFill, Consumer<Paint> updater) {

    Timeline timeline = new Timeline(Duration.millis(RGB_CHANGE_PERIOD), 
        e-> updater.accept(fills.get(currentFill.get())));
    timeline.setCycleCount(Animation.INDEFINITE);
    timeline.play();
}