【发布时间】:2017-10-26 01:31:04
【问题描述】:
我有很多重复的代码,但我不知道如何正确重构它。
我有一个类Foo,它解析从套接字接收的网络消息/数据并调用相应的onEvent() 方法。 Foo 纯粹是一个网络消息的解析器,它没有关于它接收到的事件采取什么行动的逻辑。谁想要添加这样的逻辑必须继承Foo 并覆盖onEvent() 方法。
abstract class Foo {
void processNetwotkMessage(String message) {
...
onEvent1(arg1, arg2, arg3)
reutn;
...
onEvent2(arg4);
return;
...
onEvent3()
return;
...
onEvent999(arg1337);
}
abstract protected void onEvent1(Arg1 arg1, Arg2 arg2, Arg3 arg3);
abstract protected void onEvent2(Arg4 arg4);
abstract protected void onEvent3();
...
abstract protected void onEvent999(Arg1337 arg1337);
}
现在,我的程序应该是模块化的,我有许多单独的模块类想要接收这些事件并处理它们。模块实现Plugin 接口。该接口匹配来自Foo 的onEvent() 方法,但添加了PluginContext ctx 作为第一个参数。
interface Plugin {
void onEvent1(PluginContext ctx, Arg1 arg1, Arg2 arg2, Arg3 arg3);
void onEvent2(PluginContext ctx, Arg4 arg4);
void onEvent3(PluginContext ctx);
...
void onEvent999(PluginContext ctx, Arg1337 arg1337);
}
现在,为了将事件分派给模块,我创建了 Foo 的模块感知子类,名为 PluginSupporingFoo。
class PluginSupporingFoo extends Foo implements PluginContext {
List<Plugin> plugins;
@Override
protected void onEvent1(Arg1 arg1, Arg2 arg2, Arg3 arg3) {
synchronized (plugins) {
for (Plugin p : plugins) {
p.onEvent1(this, arg1, arg2, arg3);
}
}
}
@Override
protected void onEvent2(Arg4 arg4) {
synchronized (plugins) {
for (Plugin p : plugins) {
if (PluginIsAllowedToBeAwareOfThisEvent(p, arg4)) {
p.onEvent2(this, arg4);
}
}
}
}
@Override
protected void onEvent3() {
synchronized (plugins) {
for (Plugin p : plugins) {
p.onEvent3(this);
}
}
}
...
@Override
protected void onEvent999(Arg1337 arg1337) {
synchronized (plugins) {
for (Plugin p : plugins) {
p.onEvent999(this, arg1337);
}
}
}
}
如您所见,每当Foo 调用onEvent() 方法之一时,来自PluginSupporingFoo 的被覆盖方法被调用,然后它通过调用@987654339 的相应onEvent() 方法将此事件分派给所有模块@interface,增加了一个额外的参数——PluginContext ctx。有时还有一个条件是否告诉模块一个事件,就像你在PluginSupporingFoo.onEvent2()中看到的那样。
现在,我想删除很多重复的代码。
首先,
Plugin接口和Foo类具有几乎相同的方法。实际上,Plugin接口需要具有Foo具有的所有onEvent方法,但PluginContext ctx作为额外的第一个参数。另一个代码重复在
PluginSupporingFoo。所有onEvent()方法几乎都是彼此的副本:
.
protected void on${EventName} ( ${ArgList} ) {
synchronized (plugins) {
for (Plugin p : plugins) {
${ OPTIONAL: if (filter(p, ${ArgList}.arg1)) { }
p.on{EventName}(this, ${ArgList}.allArgs);
${ OPTIONAL: } }
}
}
}
鉴于onEvent 方法有很多,拥有如此多的复制粘贴代码令人沮丧,而且如果需要,很难全部修改它们。
【问题讨论】:
-
从 Java 8 开始我们有默认方法,这意味着你不需要接口和抽象类。您可以使用该接口并为其某些方法提供默认实现。这将消除大部分代码重复。当你实现接口时,你只需要实现你没有提供实现的方法 - 除非有一个你想要重写的实现。
-
请注意接口和抽象类中的方法有不同数量的参数,因此您的建议将不起作用。
-
在那种情况下,拥有接口有什么意义呢?实现类是否覆盖了这两种方法(具有不同的签名)?
-
请阅读我的问题,它解释了什么覆盖了什么。
-
那么,抽象类Foo有什么用呢?两者都保持是没有意义的。其次,你有点实现观察者模式,所以看看它应该如何完成:如果某些插件应该只“观察”某些事件 - 你应该基于此将你的观察者和可观察对象拆分为不同的类型。这样做不仅会重构您的代码,还会通过删除以下行来减少代码:
if (PluginIsAllowedToBeAwareOfThisEvent(p, arg4))。
标签: java refactoring code-duplication