Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Configure Implementation Class of Abstract Factory with Spring

Tags:

java

spring

For my application, I have a Scale interface and multiple classes implementing this interface, for example NormalizedScale, LogScale, etc. In one of my Services, I need to create many Scales, and I want to use Spring to define which implementation of the Scale it should create. How would I implement something like this?

--

I was thinking to create a factory ScaleFactory, like in the Abstract Factory Pattern, which I could call ScaleFactory.getScale() to get a Scale of whichever implementation I configured in the Spring XML:

class ScaleFactory {
    Class<? extends Scale> scaleImplClass;
    public static Scale getScale() {
        return scaleImplClass.newInstance();
    }
}


Scale myScale = ScaleFactory.getScale();

But with that approach, how could I configure which implementation the ScaleFactory should use from Spring XML?

--

An alternative would be to make the ScaleFactory a @Service, and then autowire the ScaleFactory into my service:

@Autowired
ScaleFactory scaleFactory;

...

Scale myScale = scaleFactory.getScale();

Then I can use an autowired property in the ScaleFactory to define the scaleImplClass. But that seems weird because my Factory is also a Service and I have an instance of that factory.

--

Another approach would be to have the Class scaleImplementationClass property in my service instead of the ScaleFacotry and use the ScaleFactory like so:

@Value("${scaleImplementationClass}")
Class scaleImplementationClass

...

Scale myScale = ScaleFactory.getScale(scaleImplementationClass);

But then the factory is quite pointless because I could also just as well run scaleImplementationClass.newInstance().

like image 980
Benedikt Köppel Avatar asked Dec 25 '15 19:12

Benedikt Köppel


People also ask

Does spring use abstract factory pattern?

The Spring Framework provides the FactoryBean interface as an implementation of the Abstract Factory Pattern. A FactoryBean is a pattern to encapsulate interesting object construction logic in a class. The FactoryBean interface provides a way to customize the Spring IoC container's instantiation logic.

Does abstract factory pattern has multiple factory implementation?

Abstract Factory design pattern is one of the Creational pattern. Abstract Factory pattern is almost similar to Factory Pattern is considered as another layer of abstraction over factory pattern. Abstract Factory patterns work around a super-factory which creates other factories.


1 Answers

There are a couple of different Spring-like ways you can handle this. The approach I have personally gone for looks a bit like this:

public interface ScaleFactory {

    public Scale newInstance();
    public String type();

}

public class FirstScaleFactory implements ScaleFactory {

    public Scale newInstance() {
        return new FirstScale();
    }

    public String type() {
        return "first";
    }    

}

public class SecondScaleFactory implements ScaleFactory {

    public Scale newInstance() {
        return new SecondScale();
    }

    public String type() {
        return "second";
    }    

}

public class ScaleManager {

    private final Map<String, ScaleFactory> factories;

    @Autowired
    public ScaleManager(List<ScaleFactory> factories) {
        this.factories = factories.stream()
            .collect(Collectors.toMap(f -> f.type(), Function::identity));
    }

    public Scale newInstance(String type) {
        return Optional.ofNullable(factories.get(type))
            .map(factory -> factory.newInstance())
            .orElseThrow(IllegalArgumentException::new);
    }

}

With this approach, your ScaleManager is a standard Spring bean that can be wired into any class that needs a scale instance. At initialization time, it gets all ScaleFactories that are defined in the Spring context, and autowires them in as a List<ScaleFactory>, which is then converted to a Map (where the ScaleFactory type is the key). This avoids you needing to worry about class names of Scale, and gives your the ability to change them later (as long as you keep the type key consistent)`

Your ScaleFactory implementations can then do whatever they need to do. For example, if you have one type of Scale that you know is immutable, you can have the factory return the same instance every time. Alternatively you can have every invocation return a separate instance - the instantiation of the Scale is up to the implementation-dependent factory.

like image 186
Colin M Avatar answered Sep 27 '22 21:09

Colin M