简体   繁体   English

Java重构代码重复

[英]Java refactoring code duplication

I have code that repeats a lot, but I don't know how to refactor it properly. 我的代码重复很多,但是我不知道如何正确地重构它。

I have a class Foo , it parses the network messages/data it receives from a socket and calls the corresponding onEvent() methods. 我有一个Foo类,它解析从套接字接收的网络消息/数据,并调用相应的onEvent()方法。 Foo is purely a parser of network messages, it has no logic as to what action to take for the events it receives. Foo纯粹是网络消息的解析器,对于接收到的事件采取什么操作没有逻辑。 Whoever wants to add such logic must subclass Foo and override the onEvent() methods. 想要添加此类逻辑的任何人都必须将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);
}

Now, my program is supposed to be modular, I have many separate module classes that want to receive those events and process them. 现在,我的程序应该是模块化的,我有许多单独的模块类想要接收这些事件并对其进行处理。 The modules implement Plugin interface. 这些模块实现了Plugin接口。 The interface matches the onEvent() methods from Foo , but adds PluginContext ctx as the first argument. 该接口与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);
}

And now, to dispatch the events to the modules, I creating a module-aware subclass of Foo called PluginSupporingFoo . 现在,为了将事件调度到模块,我创建了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);
            }
        }
    }
}

As you can see, whenever Foo calls one of onEvent() methods, the overrided method from PluginSupporingFoo gets called and then it dispatches this event to all of modules by calling the corresponding onEvent() method of Plugin interface, with one extra argument added -- PluginContext ctx . 如您所见,每当Foo调用onEvent()方法之一时,都会调用PluginSupporingFoo的重写方法,然后通过调用Plugin接口的相应onEvent()方法,并向此模块分配此事件,并添加一个额外的参数- PluginContext ctx Sometimes there is also a condition whether to tell a module about an event or not, like you can see in PluginSupporingFoo.onEvent2() . 有时还存在是否要向模块告知事件的条件,就像您在PluginSupporingFoo.onEvent2()看到的PluginSupporingFoo.onEvent2()

Now, there is a lot of code duplication going on that I would like to remove. 现在,我想删除很多重复的代码。

  1. First off, Plugin interface and Foo class have almost identical methods. 首先, Plugin接口和Foo类具有几乎相同的方法。 In fact, Plugin interface needs to have all onEvent methods Foo has but with PluginContext ctx as the an extra first argument. 实际上, Plugin接口需要Foo具有的所有onEvent方法,但是将PluginContext ctx作为额外的第一个参数。

  2. Another code duplication is in PluginSupporingFoo . 另一个代码重复在PluginSupporingFoo All onEvent() methods are pretty-much a copy of each other: 所有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: } }
        }
    }
}

And given that there are many many onEvent methods, it's frustrating to have so much copy-paste code and it would be hard to modify them all if needed. 鉴于有许多onEvent方法,拥有如此多的复制粘贴代码令人沮丧,并且如果需要的话,很难修改它们。

Wow... this is a poor design to have eventXX( foo, bar, baz) etc because each time you add a new event you must add a corresponding listener method. 哇...这是一个糟糕的设计,因为它具有eventXX( foo, bar, baz)等,因为每次添加新事件时,都必须添加相应的侦听器方法。

Perhaps a better design would be to refactor this so that your Foo class only has a few or ideally one onEvent() method that takes a new Event interface 也许更好的设计是将其重构,以便您的Foo类仅具有少数几个,或者最好是一个采用新Event接口的onEvent()方法。

public class Foo{

  void onEvent(Event e){ ... }

} 

public interface Event{
     Object[] getArgs();

     //other Event specific methods
     ...
}

Then each of the eventXX methods would be a new implementation of the Event interface. 然后,每个eventXX方法将是Event接口的新实现。

public class Event2 implements Event{

   public Object[] getArgs(){
       //Arg4 like in your code
       return new Object[]{ new Arg4() };
   }
}

the Plugin could could would also similarly only have 1 method 插件也可能只有一种方法

interface Plugin{

   onEvent(PluginContext ctx, Event e);

}

Now whenever you need to add a new Event it's just a new Event implementation and these interfaces don't need any extra methods. 现在,无论何时需要添加新事件,它都只是一个新的事件实现,并且这些接口不需要任何其他方法。

Handlers can check the type of Event or you can make EventType or other kind of discriminator however you wish. 处理程序可以检查事件的类型,也可以根据需要创建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];
            ...
         }

     }
 }

Now with Java Lambdas we we could even have a handler Map<Class<? extends Event>, Function> 现在,使用Java Lambdas,我们甚至可以拥有一个处理程序Map<Class<? extends Event>, Function> Map<Class<? extends Event>, Function> if you wanted to get fancy. 如果想花哨的话,可以Map<Class<? extends Event>, Function>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM