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?

\$\endgroup\$
1
  • \$\begingroup\$ Did you read about abstract factories? \$\endgroup\$
    – Grim
    Nov 20 '14 at 15:32
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;
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.