これは、タグ付き共用体とも呼ばれるSum 型の典型的な使用例です。残念ながら、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());
}
ここでは、各クラスとインターフェイスの責任が 1 つだけになるように、懸念事項を可能な限り分離しました。実際のプロジェクトDocumentEventImpl
では、DocumentEvent
実装とDocumentEvent
インターフェースの宣言は通常、単一のクラスDocumentEvent
にマージされますが、これにより循環依存が導入され、具体的なクラス間にいくつかの依存が強制されます (そして、私たちが知っているように、インターフェースに依存することを好むはずです)。
さらに、void
通常、次のように、結果の型を表す型パラメーターに置き換える必要があります。
interface EventVisitor<R> {
R visitDocumentEvent(DocumentEvent event);
...
}
interface Event {
<R> R accept(EventVisitor<R> visitor);
}
これにより、ステートレス ビジターを使用できるようになり、非常に扱いやすくなります。
この手法によりinstanceof
、問題固有の解決策を見つけ出す必要はなく、(ほとんど?) 常に機械的に排除できます。