Java重构代码重复

时间:2017-10-26 01:31:04

标签: java refactoring code-duplication

我的代码重复了很多,但我不知道如何正确地重构代码。

我有一个类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接口。界面与onEvent()中的Foo方法匹配,但添加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的{​​{1}}的模块感知子类。

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()的覆盖方法,然后通过调用相应的{{}调度此事件到所有模块。 {1}} PluginSupporingFoo接口的方法,添加了一个额外的参数 - onEvent()。有时也会告诉模块是否告诉某个事件,就像你在Plugin中看到的一样。

现在,我想删除很多代码重复。

  1. 首先,PluginContext ctx接口和PluginSupporingFoo.onEvent2()类具有几乎相同的方法。事实上,Plugin接口需要拥有Foo个方法Plugin,但onEvent作为额外的第一个参数。

  2. 另一个代码重复在Foo。所有PluginContext ctx方法都是彼此的副本:

  3. PluginSupporingFoo

    鉴于有许多onEvent()方法,拥有如此多的复制粘贴代码令人沮丧,如果需要,很难全部修改它们。

1 个答案:

答案 0 :(得分:1)

哇...这是一个设计Foo等设计不佳的设计,因为每次添加新事件时都必须添加相应的侦听器方法。

也许更好的设计是重构这一点,以便您的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() }; } } 接口的新实现。

interface Plugin{

   onEvent(PluginContext ctx, Event e);

}

插件也可能同样只有1个方法

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]; ... } } } 或其他类型的鉴别器。

Map<Class<? extends Event>, Function>

现在有了Java Lambdas,我们甚至可以拥有一个处理程序$(document).ready(function(){ generateFeed(); }); function generateFeed(){ var index = streams.home.length - 1; while(index >= 0){ var tweet = streams.home[index]; var $tweet = $('div#main-content'); var mybox = $tweet.append('<div class="box-content"></div>'); $('<img src="" align="left" class="avatar-main">').appendTo('.box-content'); $('<h5 class="fullNameMain"> <span class="userNameMain"> <span class="timePosted"></span> </span></h5>').appendTo('.box-content'); $('<p class="tweetContent"></p>').appendTo('.box-content'); $('<ul class="activities">' + '<li><span class="comment"></span> 48K</li>' + '<li><span class="retweet"></span> 50K</li>' + '<li><span class="heart"></span> 100K</li>' + '<li><span class="msg"></span> 22K</li>' + '</ul>').appendTo('.box-content'); mybox.find('.avatar-main').attr('src', 'img/' + tweet.user + '.png'); mybox.find('.fullNameMain').prepend(tweet.user); mybox.find('span.userNameMain').prepend('@' + tweet.user); var d = new Date(); if(d.getSeconds() >= 59){ mybox.find('span.timePosted').text(' * ' + d.getMinutes() + 's ago'); }else if(d.getSeconds() < 59){ mybox.find('span.timePosted').text(' * ' + d.getMinutes() + 'm ago'); }else if(d.getMinutes() < 59){ mybox.find('span.timePosted').text(' * ' + d.getHours() + 'h ago'); } mybox.find('.tweetContent').text(tweet.message); index -= 1; } } ,如果你想得到它的想象。