Thursday, April 1, 2010

Marker Interfaces- what are they marking?

This might be a controversial statement, but I dislike marker interfaces. Yes, I get that the Serializable marker interface, for example, has a purpose. Let me amend that statement to 'I dislike marker interfaces with no clear intent'.

An interface specifies a contract. If you implement me, then you must provide these services.
An empty interface cannot specify a contract because, well, it doesn't have one to offer. It is more of a tagging mechanism. It says, if you implement me, then you're tagged in this manner. But, in most of the cases I've seen, nothing is done with this information. OK, so the class is tagged- but what the heck does that mean? Does it mean the class behaves in a certain manner? Does it mean the class can offer these services? Who knows? More often than not, marker interfaces are used as a handy mechanism to refer to classes that implement it, in a uniform manner, without the hassle of inheritance. That's about it. Which is why you'll find code riddled with if-then-elses that do an instanceOf. Kind of defeats the purpose.

What is worse about these badly designed marker interfaces, is that it's one large, no-invite-needed party; anyone and their pet elephant can tag along. Not that having the elephant would break up the party. But it isn't appropriate for the elephant to be there- the party wasn't really meant for him and passers-by would have a hard time figuring out what exactly was going on.

Let's take this very example. Your event planning application has people that are invited to parties. Just as you finish designing your Person class, along comes someone and says, we also invite entertainers to the party. The entire group is to be a single guest. Of course, they're paid and they're not expected to eat the snacks, but they're on the invite list. All your nice API's that returned collections of Person to represent the entire guest list is now left wondering what to do.

So what is usually done? Simple, lets introduce this marker interface:
public interface Invitee {} and have Person and EntertainmentGroup implement it. Then all we do is change our API to return Invitees and we're done.
What does it mean to be an invitee? Nothing.
Now you need to find out how many snacks to order assuming that each person will eat 5. The code I see more often than not is, get a collection of Invitees from the guest list, iterate through them, check if the Invitee is an instanceOf Person- and increment the snack counter by 5.
What did it mean to be an invitee? Nothing.
Tomorrow when the zoo keeper is invited to the party and insists on bringing his pet elephant, what do you do? Simple. Have Elephant implement Invitee. Then when you calculate the amount of snacks to order, you add yet another check to see if the Invitee is an instanceOf Elephant and you add 50 kilos of bananas to the list.
Ideally the Invitee class would specify what it means to be an invitee. It's behavior is predictable. When the event manager gets rich and decides that only movie stars can attend his parties, then you can no longer have Invitee extend MovieStar, unless you only know elephants that are movie stars.

Unless you are doing something very concrete with the marker interface, unless you are processing that tag information in some manner, I consider it a Bad Thing.
Tagging can be accomplished using annotations. You can selectively tag classes/methods and actually process them to do or mean something useful.

What do you think? Do you see marker interfaces being used as convenience mechanisms?

-Luanne

5 comments:

Anonymous said...

No, you make Invitee a parent class. Probably an abstract class that has a method the children need to implement and that method determines the difference between the types.

You are correct, using a marker interface in this way isn't a good idea.

thought-bytes said...

The reason that Invitee is almost never a parent class is because Person, EntertainmentGroup and Elephant already extend some other class. Hence the solution is the marker interface!

Aditi said...

That sounds like a wrong design. We should not use marker interface for such scenario's. Marker interface, as I understand should only be done if there is some business logic to be performed based on that or there is some implicit behavior attached to it. Like as you said, Serializable. The moment we declare that, Java knows what to do with the class. For the example you gave, the behavior changes with each kind of invitee, so each invitee should implement method like getSnackConsumption() or something of that sort. Marker doesn't make sense here, but I agree that's a common mistake.

Nice observation!

Jay said...
This comment has been removed by the author.
Jay said...

Good observation.. its commonly done this way, because ppl don't like to change much code when new requirements like, EntertainmentGroup as Invitee, comes in and try to find solution with minimal code change.
Solution to add Invitee as an Interface is correct but not as a Marker interface. Your if - else logic should move to contract definition of the class that implements Invitee interface with contract defined in Invitee interface. This way Code looks cleaner, understandable, has meaning and is maintainable.