Choose a concrete implementation at runtime with Java 8
Asked Answered
P

2

13

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?
Perrault answered 20/3, 2015 at 15:42 Comment(2)
Are you perhaps looking for the #708836?Firedamp
Something along those lines, but also if it's a good idea avoiding the factory class, and putting that in the interface itself.Perrault
S
8

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

Sephira answered 20/3, 2015 at 15:48 Comment(4)
"Thanks to such solution, all the developer has to do if he needs new implementation, is to just create it.". But he, or someone, will need to define the criteria for choosing one of the implementations, right? And the criteria goes in the interface?Perrault
Yes and No - Interface force implementing class to provide such criteria by declaring some kind of method eg. getProcessingType. When creating implementation for new "ProcessingType" you developer will provide criteria while creating it.Sephira
Going back to my question. What you propose is having a Factory class, with a single static method, right?Perrault
@Antoniossss, I really like your approach but just checking if you are still using the same or made any updates/changes. Also, any challenges that you have faced in this approach?Gear
F
3

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.

Firedamp answered 20/3, 2015 at 15:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.