这是Sum types的典型用例,也称为标记联合。不幸的是,Java 不直接支持它们,因此必须使用访问者模式的一些变体来实现它们。
interface DocumentEvent {
// stuff specific to document event
}
interface MailEvent {
// stuff specific to mail event
}
interface EventVisitor {
void visitDocumentEvent(DocumentEvent event);
void visitMailEvent(MailEvent event);
}
class EventDivider implements EventVisitor {
@Override
void visitDocumentEvent(DocumentEvent event) {
documentGenerator.gerenateDocument(event);
}
@Override
void visitMailEvent(MailEvent event) {
deliveryManager.deliverMail(event);
}
}
这里我们定义了我们的EventDivider
, 现在提供一个调度机制:
interface Event {
void accept(EventVisitor visitor);
}
class DocumentEventImpl implements Event {
@Override
void accept(EventVisitor visitor) {
visitor.visitDocumentEvent(new DocumentEvent(){
// concrete document event stuff
});
}
}
class MailEventImpl implements Event { ... }
public void divideEvent(Event event) {
event.accept(new EventDivider());
}
在这里,我使用了最大可能的关注点分离,以便每个类和接口的责任是唯一的。在现实生活中的项目DocumentEventImpl
中,DocumentEvent
实现和DocumentEvent
接口声明通常合并到一个类DocumentEvent
中,但这会引入循环依赖并强制具体类之间存在一些依赖关系(正如我们所知,人们应该更喜欢依赖接口)。
此外,void
通常应该用类型参数替换来表示结果类型,如下所示:
interface EventVisitor<R> {
R visitDocumentEvent(DocumentEvent event);
...
}
interface Event {
<R> R accept(EventVisitor<R> visitor);
}
这允许使用无状态访问者,这非常好处理。
这种技术允许(几乎?)总是instanceof
机械地消除,而不必找出特定问题的解决方案。