Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Choose a concrete implementation at runtime with Java 8

I'm not clear about where to put the if/switch when choosing what implementation/subclass to instantiate, specially when considering that now interfaces can have static methods.

Let's say I have a service, a type defined by an interface and a couple of implementations. I guess that it'd be better not to put that logic in the service, but to have factory method. But should it go in the interface or in another class with a param-to-type map as suggested in this answer?

It seems natural to me to put it in the interface:

public interface MyInterface
{
    public void doSomething();

    public static MyInterface create(int param)
    {
        if (param == 0)
            return new ImplA();
        else
            return new ImplB();
    }
}

and then just simply call it from the service:

public class MyService
{
    public void serveMe(int param)
    {
        MyInterface.create(param).doSomething();
    }
}

But I don't know if it's bad having the interface knowing about its implementation, or a parent class knowing about its subtypes. So

  1. Where should I put that logic?
  2. Would that change a lot if I'm choosing subclasses of a type?
like image 785
user3748908 Avatar asked Mar 20 '15 15:03

user3748908


2 Answers

Use Factory for this. This way you will be able to maintain single responsibility principle. In one of my own projects interface however defines method that determines for what type of argument should this particular implementation be used. Thanks to this and using Reflections, whole process is automated. Reflections finds all classes that implements given interface and store its 'usage-type' in a map for fast lookup. Thanks to such solution, all the developer has to do if he needs new implementation, is to just create it. No other modifications are required in other parts of the system, not even in factory class.

Reflections has nice feature to store metadata on compile time, so runtime lookup for proper classes is a blink of an eye

like image 52
Antoniossss Avatar answered Sep 28 '22 09:09

Antoniossss


There are quite a few solutions to your problem, I think you are aware of many of them already.

The static factory method pattern

interface Interface {
    public static Interface create(...);
}

This works, however it make separation of interface and implementation difficult. The interface must know of all possible implementations and it is not particularly extensible. To add a new implementation you need to change the interface.

Factory pattern

This is more or less old-school by the book GOF:

interface Factory {
    public Interface create(...)
}

This allows you to replace the factory (and even stack factories). It has --however-- the drawback that you need to pass around the factory object. Note that with Java 8 you also have the ability to use very lightweight lambda-based factories (see https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html)

Containers

Another solution, although it can be quite heavyweight is to leave construction of the object to a container framework. In those cases, the container provides your object factory. The actual type of object is left to configuration. Spring and Java EE do quite a job of this. Also combine with dependency injection for added effect.

These are at least those I can think of.

like image 43
dhke Avatar answered Sep 28 '22 09:09

dhke