1
\$\begingroup\$

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?

asked Nov 20, 2014 at 10:01
\$\endgroup\$
1
  • \$\begingroup\$ Did you read about abstract factories? \$\endgroup\$ Commented Nov 20, 2014 at 15:32

1 Answer 1

1
\$\begingroup\$

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;
 }
}
answered Nov 25, 2014 at 7:51
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.