我有两种方法可以使用Circle
或Scene
,并通过每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);
}
显然这些非常相似,但是由于Circle
和Scene
不在同一个继承树中,我不能使用调用它们的超类的方法包含{{1} } / .setFill()
方法。
我如何在这里删除代码重复?
答案 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();
}