我将用一个例子来解释。我的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提供了有关此问题的更多信息。
答案 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个模块工作?
一个答案是你可能想要彻底修改一个实现而不是其他实现 - 现在你已经将它简化为一个方法,所有这些都属于那个切换案例。另一个是,一旦以这种方式简化,倾向于进一步简化 - 可能将create
和update
组合成一种方法。完成此操作后,所有被调用者必须确保完成该方法合同的所有可能细节,而不仅仅是一个特定的合同。
如果这些事件的接收者很简单并且仍然如此,那么可能没有充分的理由不仅仅有一个ModelModifiedEvent显然足够通用于所有可能的用例 - 可能只是包装ID以请求所有客户端模块刷新他们对该对象的看法。如果出现未来的用例只有一种事件很重要,那么现在必须更改事件,所有导致事件创建的网站都必须更改,以便正确填充此新字段。
Java商店通常不使用Java,因为它是最漂亮的语言,或者因为它是编写或找到开发人员最简单的语言,但因为它相对容易维护和重构。在设计API时,重要的是要考虑未来的需求,同时考虑修改当前API需要什么 - 您的IDE几乎肯定有一个快捷键来查找特定方法或构造函数的所有调用,允许您轻松找到使用它的所有地方并更新它们。因此,请考虑您期望的其他用例,以及其他代码库的易用性。
最后,不要忘记泛型 - 对于上面的例子,我可能会创建一个DtoServiceInterface来简化问题,因此我只用三种方法声明一个接口,并实现它并根据需要引用它。以同样的方式,您可以创建一组三个GwtEvent
类型(带*Handler
接口,也可能Has*Handlers
),但保留所有可能类型的通用类型。在这里考虑com.google.gwt.event.logical.shared.SelectionEvent<T>
作为示例 - 在您的情况下,您可能希望使模型对象类型成为参数,以便处理程序可以检查它们正在处理哪种类型的事件(请记住,泛型在Java中被擦除),或者来自每个模型类型的EventBus
个。{/ p>