I use JPA inheritance with JOIN strategy (JPA2/Hibernate). I have an abstract general Event entity with shared fields (date, time, place etc), and its children, let's say OutdoorEvent, ClassicalMusicEvent etc. with specific fields for each type. I make a search over all Event's, getting a List<Event>
which I display. The processing for each event type is different though, so I need to figure out the type of event for each Event object. Now here's the problem. I came up with two solutions. First, the instanceof
keyword:
if (event instanceof OutdoorEvent) {
...
} else if (event instanceof OtherKindOfEvent) {
...
} etc.
Second, I add a transient enum field to the Event entity and set this field in every children type's constructor. Then I could do:
if (event.getType() == EventType.OutdoorEvent) {
...
} else if (event.getType() == EventType.OtherKindOfEvent) {
...
} etc.
Which solution is better, or more OOP? Is there any other solution to this?
This is a good question because the optimal OOP solution would be to use polymorphism. On your abstract Event class add an abstract 'process' method and then in your subclasses implement the required processing. Then you can just call
process()
and don't care what the type of subclass it is.However, you probably want to keep your Event (i.e. data) classes decoupled from the logic so somewhere you're probably going to end up doing
instanceof
or something like your enum.I have no preference which, it is possible that one is faster than the other and I would probably go with the enum rather than instanceof for speed (keen to hear if anyone has insight on that).
If you do go with the enum In your example with the events, you should use a switch instead of if..else.
The most OOP approach would be to use the visitor pattern.
Put the display handling logic in a Visitor:
And then on each subclass have:
Then instead of the multiple if-checks you just do:
Apart from that,
instanceof
looks cleaner.If you deal with Hibernate then you should prepare yourself for cases with Hibernate Proxies (see e.g. Casting Hibernate Proxies to Subclasses): in your example variable event might be a dynamically created instance of HibernateProxy, and
event instanceof OtherKindOfEvent
will not work in this case.So you will either need to de-proxy (using Hibernate utilities and loosing JPA abstraction), or use approach like you've mentioned. So my personal preference is the second option (or anything similar to it).
Simple strategy pattern: