Frage

Over the last few months, I stumbled a few times over the following technique / pattern. However, I can't seem to find a specific name, nor am I a 100% sure about all its advantages and disadvantages.

The pattern goes as follows:

Within a Java interface, a set of common methods is defined as usual. However, using an inner class, a default instance is leaked through the interface.

public interface Vehicle {
    public void accelerate();
    public void decelerate();

    public static class Default {
         public static Vehicle getInstance() {
             return new Car(); // or use Spring to retrieve an instance
         }
    }
 }

For me, it seems that the biggest advantage lies in the fact that a developer only needs to know about the interface and not its implementations, e.g. in case he quickly wants to create an instance.

 Vehicle someVehicle = Vehicle.Default.getInstance();
 someVehicle.accelerate();

Furthermore, I have seen this technique being used together with Spring in order to dynamically provide instances depending on the configuration. In this regard, it also looks like this can help with modularization.

Nevertheless, I can't shake the feeling that this is a misuse of the interface since it couples the interface with one of its implementations. (Dependency inversion principle etc..) Could anybody please explain to me how this technique is called, as well as its advantages & disadvantages?

Update:

After some time for consideration, I rechecked and noticed that the following singleton version of the pattern was used far more often. In this version, a public static instance is exposed through the interface which is initialized only once (due to the field being final). In addition, the instance is almost always retrieved using Spring or a generic factory which decouples the interface from the implementation.

public interface Vehicle {
      public void accelerate();
      public void decelerate();

      public static class Default {
           public static final Vehicle INSTANCE = getInstance();

           private static Vehicle getInstance() {
                return new Car(); // or use Spring/factory here
           }
      }
 }

 // Which allows to retrieve a singleton instance using...
 Vehicle someVehicle = Vehicle.Default.INSTANCE;

In a nutshell: it seems that this is a custom singleton/factory pattern, which basically allows to expose an instance or a singleton through its interface. With respect to the disadvantages, a few have been named in the answers & comments below. So far, the advantage seems to lie in its convenience.

War es hilfreich?

Lösung

Default.getInstance is IMHO just a very specific form of a factory method, mixed up with a naming convention taken from the singleton pattern (but without being an implementation of the latter). In the current form this is a violation of the "single responsibility principle", because the interface (which already serves the purpose of declaring a class API) takes the additional responsibility of providing a default instance, which would be much better placed in a separate VehicleFactory class.

The main problem caused by this construct is that it induces a cyclic dependency between Vehicle and Car. For example, in the current form it won't be possible to place Vehicle in one library, and Car in another. Using a separate factory class and placing the Default.getInstance method there would solve that problem. It may be also a good idea to give that method a different name, to prevent any confusion related to singletons. So the result could be something like

VehicleFactory.createDefaultInstance()

Andere Tipps

This looks like Null Object pattern to me.

But that heavily depends on how Car class is implemented. If it is implemented in "neutral" way, then it is definitely a Null Object. That means, if you can remove all null checks on the interface and put instance of this class instead of each occurrence of null, then code still has to work correctly.

Also if it is this pattern, then there is no problem of creating tight coupling between the interface itself and implementation of null object. Because null object can to be everywhere where said interface is used.

Lizenziert unter: CC-BY-SA mit Zuschreibung
scroll top