我的代码重复了很多,但我不知道如何正确地重构代码。
我有一个类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
中看到的一样。
现在,我想删除很多代码重复。
首先,PluginContext ctx
接口和PluginSupporingFoo.onEvent2()
类具有几乎相同的方法。事实上,Plugin
接口需要拥有Foo
个方法Plugin
,但onEvent
作为额外的第一个参数。
另一个代码重复在Foo
。所有PluginContext ctx
方法都是彼此的副本:
PluginSupporingFoo
鉴于有许多onEvent()
方法,拥有如此多的复制粘贴代码令人沮丧,如果需要,很难全部修改它们。
答案 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;
}
}
,如果你想得到它的想象。