I was wondering how I could implement the simple factory pattern with Spring 3 annotations. I saw in the documentation that you can create beans that call the factory class
Based on solution by Pavel Černý here we can make an universal typed implementation of this pattern. To to it, we need to introduce NamedService interface:
public interface NamedService {
String name();
}
and add abstract class:
public abstract class AbstractFactory {
private final Map map;
protected AbstractFactory(List list) {
this.map = list
.stream()
.collect(Collectors.toMap(NamedService::name, Function.identity()));
}
/**
* Factory method for getting an appropriate implementation of a service
* @param name name of service impl.
* @return concrete service impl.
*/
public T getInstance(@NonNull final String name) {
T t = map.get(name);
if(t == null)
throw new RuntimeException("Unknown service name: " + name);
return t;
}
}
Then we create a concrete factory of specific objects like MyService:
public interface MyService extends NamedService {
String name();
void doJob();
}
@Component
public class MyServiceFactory extends AbstractFactory {
@Autowired
protected MyServiceFactory(List list) {
super(list);
}
}
where List the list of implementations of MyService interface at compile time.
This approach works fine if you have multiple similar factories across app that produce objects by name (if producing objects by a name suffice you business logic of course). Here map works good with String as a key, and holds all the existing implementations of your services.
if you have different logic for producing objects, this additional logic can be moved to some another place and work in combination with these factories (that get objects by name).