Tom Butler's programming blog

Empty interfaces are bad practice

Empty "marker" interfaces

Empty interfaces (also known as "marker interfaces") are often used to mark a class for its indended purpose.

They exist for the sole purpose to make it possible so that the client code which is using the object that implements the marker interface can treat the object in a specific manner. Generally, like this:

interface Bar {}

class 
Foo implements Bar {

}

//Client code...
$foo = new Foo;

if (
$foo instanceof Bar) {
    
//...
}
else {
    
//...
}

This allows some rudimentary type checking and gives the Foo class control over how it should be used by its clients.

But that is precisely the problem. This approach breaks encapsulation and the Single Responsibility Principle. The object itself now has indirect control over how it will be used externally. Moreover, it has knowledge of the system it's going to be used in. By applying the marker interface, the class definition is suggesting it expects to be used somewhere that checks for the existence of the marker. It has implicit knowledge of the environment it's used in and is trying to define how it should be being used. This goes directly against the idea of encapsulation because the class implementing the interface has knowledge of the implementation details of a part of the system that exists entirely outside its own scope.

By using marker interfaces in this way, the class now has two jobs, exposing its own interface and telling the outside world how it should be used. This is a discreet violation of the Single Responsibility Principle. In the same way the singleton pattern violates it by enforcing how the class can be used, marker interfaces hint at the same problem.

At a practical level this reduces portability and reusability. If the class is re-used in a different application, the interface needs to be copied across too, and it may not have any meaning in the new environment, making it entirely redundant.

In the example above, if the Foo class is isolated, the interface Bar is entirely meaningless. Because of this, the "marker" is metadata about the class and nothing to do with the class itself. This metadata is not used by the class and is only meaningful to (some) external client code so that it knows it should treat the object in a certain manner. Because it only has meaning to the client code, the metadata should be in the client code, not the class API.

The same is partly true of normal interfaces, however, the difference between a "marker interface" and a normal interface is that an interface with methods tells the outside world how an object can be used and exposes method APIs. In this case, any behaviour that exists because of the interface is encapsulated in the class itself. On the other hand, the behaviour that exists because of the marker interface exists beyond the scope of the class. As such, the class cannot guarantee to fulfill its responsibility because part of it must be handled externally.