看似冗余的事件和事件处理程序

时间:2013-03-23 17:03:26

标签: events gwt event-handling

我将用一个例子来解释。我的GWT项目有一个公司模块,允许用户添加,编辑,删除,选择和列出公司。

其中,添加,编辑和删除操作将用户退回到CompanyList页面。 因此,有三个不同的事件 - CompanyAddedEvent, CompanyUpdatedEvent and CompanyDeletedEvent及其各自的事件处理程序 - 对我来说似乎有些过分,因为它们的功能绝对没有区别。

让单个事件管理这三个操作是否可以? 我认为另一种选择是使用像CompanyListInvokedEvent这样的事件。但是,在某些地方我认为它不合适,事件实际上不是被调用的列表,而是被添加/更新/删除的公司。

如果它只是一个单独的模块,我将完成三个独立事件的任务。但其他10个这样的模块正面临着这种困境。这意味着10x3 = 30个事件类以及它们各自的30个处理程序。这个数字足以让我重新考虑。 什么是一个很好的解决方案?

更新 -

@ColinAlworth的回答让我意识到我可以轻松使用Generics而不是我的愚蠢解决方案。以下代码表示事件EntityUpdatedEvent,每当更新实体时都会引发该事件。

事件处理程序类 -

public class EntityUpdatedEvent<T> extends GwtEvent<EntityUpdatedEventHandler<T>>{

    private Type<EntityUpdatedEventHandler<T>> type;
    private final String statusMessage;

    public EntityUpdatedEvent(Type<EntityUpdatedEventHandler<T>> type, String statusMessage) {
        this.statusMessage = statusMessage;
        this.type = type;
    }

    public String getStatusMessage() {
        return this.statusMessage;
    }

    @Override
    public com.google.gwt.event.shared.GwtEvent.Type<EntityUpdatedEventHandler<T>> getAssociatedType() {
        return this.type;
    }

    @Override
    protected void dispatch(EntityUpdatedEventHandler<T> handler) {
        handler.onEventRaised(this);
    }
}

事件处理程序接口 -

public interface EntityUpdatedEventHandler<T> extends EventHandler {
    void onEventRaised(EntityUpdatedEvent<T> event);
}

将处理程序添加到事件总线 -

eventBus.addHandler(CompanyEventHandlerTypes.CompanyUpdated, new EntityUpdatedEventHandler<Company>() {

    @Override
    public void onEventRaised(EntityUpdatedEvent<Company> event) {
        History.newItem(CompanyToken.CompanyList.name());
        Presenter presenter = new CompanyListPresenter(serviceBundle, eventBus, new CompanyListView(), event.getStatusMessage());
        presenter.go(container);
    }
});

同样,我还有两个其他已添加和已删除的通用事件,从而消除了与事件相关的代码库的全部冗余。

对此解决方案有任何建议吗?

P.S。 &GT; This discussion提供了有关此问题的更多信息。

1 个答案:

答案 0 :(得分:4)

要回答这个问题,让我首先提出另一种思考同类问题的方法 - 而不是事件,我们只会使用方法。

在我的分层应用程序中,两个模块通过接口进行通信(注意这些方法都是void,因此它们更像是事件 - 调用者不期待回复):

package com.acme.project;

public interface CompanyServiceInteface {
  public void addCompany(CompanyDto company) throws AcmeBusinessLogicException;

  public void updateCompany(CompanyDto company) throws AcmeBusinessLogicException;

  public void deleteCompany(CompanyDto company) throws AcmeBusinessLogicException;
}

这对我来说似乎有些过分 - 为什么不将这个API的大小减少到一个方法,并添加一个枚举参数来简化这个。这样,当我构建一个替代实现或需要在我的单元测试中模拟它时,我只有一个方法来构建而不是三个。当我完成其余的应用程序时,这显然有点过头了 - 为什么不只是ObjectServiceInterface.modify(Object someDto, OperationEnum invocation);才能为所有10个模块工作?


一个答案是你可能想要彻底修改一个实现而不是其他实现 - 现在你已经将它简化为一个方法,所有这些都属于那个切换案例。另一个是,一旦以这种方式简化,倾向于进一步简化 - 可能将createupdate组合成一种方法。完成此操作后,所有被调用者必须确保完成该方法合同的所有可能细节,而不仅仅是一个特定的合同。

如果这些事件的接收者很简单并且仍然如此,那么可能没有充分的理由不仅仅有一个ModelModifiedEvent显然足够通用于所有可能的用例 - 可能只是包装ID以请求所有客户端模块刷新他们对该对象的看法。如果出现未来的用例只有一种事件很重要,那么现在必须更改事件,所有导致事件创建的网站都必须更改,以便正确填充此新字段。

Java商店通常不使用Java,因为它是最漂亮的语言,或者因为它是编写或找到开发人员最简单的语言,但因为它相对容易维护和重构。在设计API时,重要的是要考虑未来的需求,同时考虑修改当前API需要什么 - 您的IDE几乎肯定有一个快捷键来查找特定方法或构造函数的所有调用,允许您轻松找到使用它的所有地方并更新它们。因此,请考虑您期望的其他用例,以及其他代码库的易用性。

最后,不要忘记泛型 - 对于上面的例子,我可能会创建一个DtoServiceInterface来简化问题,因此我只用三种方法声明一个接口,并实现它并根据需要引用它。以同样的方式,您可以创建一组三个GwtEvent类型(带*Handler接口,也可能Has*Handlers),但保留所有可能类型的通用类型。在这里考虑com.google.gwt.event.logical.shared.SelectionEvent<T>作为示例 - 在您的情况下,您可能希望使模型对象类型成为参数,以便处理程序可以检查它们正在处理哪种类型的事件(请记住,泛型在Java中被擦除),或者来自每个模型类型的EventBus个。{/ p>