I have the following (maybe common) problem and it absolutely puzzles me at the moment:
There are a couple of generated event objects which extends the abstract clas
This is a typical use case for Sum types, also known as tagged unions. Unfortunately, Java does not support them directly, so they have to be implemented using some variation of the visitor pattern.
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);
}
}
Here we have defined our EventDivider, now to provide a dispatch mechanism:
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());
}
Here I used maximum possible separation of concerns so that responsibility of each class and interface is one and only one. In real life projects DocumentEventImpl, DocumentEvent implementation and DocumentEvent interface declaration are usually merged into a single class DocumentEvent, but that introduces circular dependencies and forces some dependencies between concrete classes (and as we know, one should prefer to depend on interfaces).
Additionally, void should usually be replaced with a type parameter to represent the result type, like this:
interface EventVisitor {
R visitDocumentEvent(DocumentEvent event);
...
}
interface Event {
R accept(EventVisitor visitor);
}
This allows one to use stateless visitors, which are very nice to deal with.
This technique allows to (almost?) always eliminate instanceof mechanically rather than having to figure out a problem-specific solution.