Reputation: 5341
I'm developing a Web application using Spring.
I have a common abstract class and many implementions of it.
Now, in a controller, depending on some parameter, I need different implementations of it.
This can be easily implemented with Factory Pattern.
For example:
abstract class Animal{
public abstract void run(){
}
}
class Dog extends Animal{
...
}
Class Cat extends Animal{
...
}
Now with factory pattern, I can create a factory class with a factory method which creates Animals based on some parameter. But I don't want to create instances on my own.
I need the same functionality, but I want Spring to manage everything. Because different implementations have their dependencies and I want them to be injected by Spring.
What is the best way of handling this situation?
Upvotes: 1
Views: 184
Reputation: 124601
Configure the beans you want to be created as prototype beans. Next create a factory which basically knows which bean to retrieve from the application context based on the input (so instead of creating them you basically let spring do the heavy lifting).
Defining the components can be done with either @Component
combinded with @Scope("prototype")
or by using XML configuration.
abstract class Animal{
public abstract void run(){}
}
@Component
@Scope("prototype")
class Dog extends Animal{}
@Component
@Scope("prototype")
Class Cat extends Animal{}
And an AnimalFactory
to complete the answer.
@Component
public class AnimalFactory implements BeanFactoryAware {
private BeanFactory factory;
public Animal create(String input) {
if ("cat".equals(input) ) {
return factory.getBean(Cat.class);
} else if ("dog".equals(input) ) {
return factory.getBean(Dog.class);
}
}
public void setBeanFactory(BeanFactory beanFactory) {
this.factory=beanFactory;
}
}
Upvotes: 1
Reputation:
In addition to JB's answer, you can also use XML-based configuration. The following will work as well:
package com.example;
class PetOwner(){
private Animal animal;
public PetOwner() {
};
public void setAnimal(Animal animal) {
this.animal = animal;
}
}
with the following xml-config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="petOwner" class="com.example.PetOwner">
<property name="animal" ref="animal" />
</bean>
<bean id="animal" class="com.example.pets.Dog" scope="prototype" />
The prototype-scope will return a new instance every time a request for the object is made. See http://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch04s04.html
Upvotes: 0
Reputation: 691785
@Component
public class AnimalFactory {
@Autowired
private Dog dog;
@Autowired
private Cat cat;
public Animal create(String kind) {
if (king.equals("dog") {
return dog;
}
else {
return cat;
}
}
}
@Component
public class Cat extends Animal {
...
}
@Component
public class Dog extends Animal {
...
}
@Component
private class Client {
@Autowired
private AnimalFactory factory;
public void foo() {
Animal animal = factory.create("dog");
animal.run();
}
}
Upvotes: 1