Java重构代码重复
Java refactoring code duplication
我有很多重复的代码,但我不知道如何正确重构它。
我有一个 class Foo
,它解析从套接字接收的网络 messages/data 并调用相应的 onEvent()
方法。 Foo
纯粹是网络消息的解析器,对于接收到的事件采取什么行动没有逻辑。任何想要添加此类逻辑的人都必须 subclass 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);
}
现在,我的程序应该是模块化的,我有许多单独的模块 classes 想要接收这些事件并处理它们。这些模块实现了 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
的模块感知子 class,名为 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
中的覆盖方法,然后通过调用Plugin
接口的相应 onEvent()
方法,添加了一个额外的参数 -- PluginContext ctx
。有时还有一个条件是否告诉模块有关事件的信息,就像您在 PluginSupporingFoo.onEvent2()
.
中看到的那样
现在,我想删除大量重复代码。
首先,Plugin
接口和Foo
class有几乎相同的方法。事实上,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
方法,复制粘贴代码如此之多令人沮丧,如果需要,很难全部修改。
哇...这是一个糟糕的设计 eventXX( foo, bar, baz)
等等,因为每次添加新事件时都必须添加相应的侦听器方法。
也许更好的设计是重构它,这样你的 Foo
class 就只有几个或理想情况下只有一个 onEvent()
方法需要一个新的 Event
接口
public class Foo{
void onEvent(Event e){ ... }
}
public interface Event{
Object[] getArgs();
//other Event specific methods
...
}
那么每个 eventXX
方法都将是 Event
接口的新实现。
public class Event2 implements Event{
public Object[] getArgs(){
//Arg4 like in your code
return new Object[]{ new Arg4() };
}
}
插件可能也可能同样只有 1 个方法
interface Plugin{
onEvent(PluginContext ctx, Event e);
}
现在,只要您需要添加一个新的事件,它只是一个新的事件实现,这些接口不需要任何额外的方法。
处理程序可以检查事件的类型,或者您可以根据需要制作 EventType
或其他类型的鉴别器。
class MyPlugin implements Plugin{
public void onEvent(PluginContext ctx, Event e){
//this is only useful if we only care about a few types
if( e instanceOf Event2){
//we know this is Arg4
Arg4 arg4 = (Arg4) e.getArgs()[0];
...
}
}
}
现在有了 Java Lambda,我们甚至可以有一个处理程序 Map<Class<? extends Event>, Function>
如果你想变得更漂亮的话。
我有很多重复的代码,但我不知道如何正确重构它。
我有一个 class Foo
,它解析从套接字接收的网络 messages/data 并调用相应的 onEvent()
方法。 Foo
纯粹是网络消息的解析器,对于接收到的事件采取什么行动没有逻辑。任何想要添加此类逻辑的人都必须 subclass 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);
}
现在,我的程序应该是模块化的,我有许多单独的模块 classes 想要接收这些事件并处理它们。这些模块实现了 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
的模块感知子 class,名为 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
中的覆盖方法,然后通过调用Plugin
接口的相应 onEvent()
方法,添加了一个额外的参数 -- PluginContext ctx
。有时还有一个条件是否告诉模块有关事件的信息,就像您在 PluginSupporingFoo.onEvent2()
.
现在,我想删除大量重复代码。
首先,
Plugin
接口和Foo
class有几乎相同的方法。事实上,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
方法,复制粘贴代码如此之多令人沮丧,如果需要,很难全部修改。
哇...这是一个糟糕的设计 eventXX( foo, bar, baz)
等等,因为每次添加新事件时都必须添加相应的侦听器方法。
也许更好的设计是重构它,这样你的 Foo
class 就只有几个或理想情况下只有一个 onEvent()
方法需要一个新的 Event
接口
public class Foo{
void onEvent(Event e){ ... }
}
public interface Event{
Object[] getArgs();
//other Event specific methods
...
}
那么每个 eventXX
方法都将是 Event
接口的新实现。
public class Event2 implements Event{
public Object[] getArgs(){
//Arg4 like in your code
return new Object[]{ new Arg4() };
}
}
插件可能也可能同样只有 1 个方法
interface Plugin{
onEvent(PluginContext ctx, Event e);
}
现在,只要您需要添加一个新的事件,它只是一个新的事件实现,这些接口不需要任何额外的方法。
处理程序可以检查事件的类型,或者您可以根据需要制作 EventType
或其他类型的鉴别器。
class MyPlugin implements Plugin{
public void onEvent(PluginContext ctx, Event e){
//this is only useful if we only care about a few types
if( e instanceOf Event2){
//we know this is Arg4
Arg4 arg4 = (Arg4) e.getArgs()[0];
...
}
}
}
现在有了 Java Lambda,我们甚至可以有一个处理程序 Map<Class<? extends Event>, Function>
如果你想变得更漂亮的话。