My problem is quite straightforward. I want to build a factory, but the kind of object returned depends on a value read from a bean that is somehow a cache. So of course, I can't call the bean's method from the static method in the factory:
public interface FinderService
{
public String find(String name);
}
public class GeneralFinderService implements FinderService
{
@Override
public String find(String name)
{
return "general name";
}
}
public class NorthFinderService implements FinderService
{
@Override
public String find(String name)
{
return "place in the north";
}
}
public class SouthFinder implements FinderService
{
@Override
public String find(String name)
{
return "guy in the south";
}
}
public class TestFinder
{
public static void main(String[] args)
{
FinderService finderService = FinderFactory.getFinderService("my location");
finderService.find("some guy");
}
}
The options I think I have right now are either make the factory a bean, or use AppContext.getBean to get the bean in the factory. I like neither of them.
Option 1: make the factory a bean
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("finderFactory")
public class FinderFactory
{
@Autowired
private LocationCache locationCache;
public FinderService getFinderService(String location)
{
if (locationCache.isInNorth(location))
{
return new NorthFinderService();
}
else if (locationCache.isInSouth(location))
{
return new SouthFinder();
}
else
{
return new GeneralFinderService();
}
}
}
Option 2: get the bean from the appcontext
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class FinderFactory
{
private static LocationCache locationCache = (LocationCache) new ClassPathXmlApplicationContext().getBean("locationCache");
public static FinderService getFinderService(String location)
{
if (locationCache.isInNorth(location))
{
return new NorthFinderService();
}
else if (locationCache.isInSouth(location))
{
return new SouthFinder();
}
else
{
return new GeneralFinderService();
}
}
}
Is there a better approach?
-
\$\begingroup\$ Did you read about abstract factories? \$\endgroup\$Grim– Grim2014年11月20日 15:32:29 +00:00Commented Nov 20, 2014 at 15:32
1 Answer 1
This looks like example code so I won't go into detail. If I had to choose between the two, I'd go with the first, because you should not be instantiating application contexts like this. There should be ONE application context and it should be created in main
or ServletContextListener.contextInitialized
or some such initialization method. In general service classes should be singleton scope (as opposed to prototype scope, not related to singleton pattern). Which means they should not be created using new
in code.
@Component("finderFactory")
public class FinderFactory { // use standard java braces
@Autowired private LocationCache locationCache;
@Autowired private NorthFinderService northFinderService;
@Autowired private SouthFinderService southFinderService; // use consistent names
@Autowired private GeneralFinderService generalFinderService;
public FinderService getFinderService(String location) {
if (locationCache.isInNorth(location))
return northFinderService;
// you don't have to use `else`
// when `if` is followed by a `return`.
if (locationCache.isInSouth(location))
return southFinderService;
return generalFinderService;
}
}
Explore related questions
See similar questions with these tags.