javaspringannotationsfactory-pattern

Implement a simple factory pattern with Spring 3 annotations


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 and run a factory method. I was wondering if this was possible using annotations only.

I have a controller that currently calls

MyService myService = myServiceFactory.getMyService(test);
result = myService.checkStatus();

MyService is an interface with one method called checkStatus().

My factory class looks like this:

@Component
public class MyServiceFactory {

    public static MyService getMyService(String service) {
        MyService myService;
        
        service = service.toLowerCase();
        
        if (service.equals("one")) {
            myService = new MyServiceOne();
        } else if (service.equals("two")) {
            myService = new MyServiceTwo();
        } else if (service.equals("three")) {
            myService = new MyServiceThree();
        } else {
            myService = new MyServiceDefault();
        }
        
        return myService;
    }
}

MyServiceOne class looks like this :

@Autowired
private LocationService locationService;

public boolean checkStatus() {
      //do stuff
}

When I run this code the locationService variable is always null. I believe this is because I am creating the objects myself inside the factory and autowiring is not taking place. Is there a way to add annotations to make this work correctly?

Thanks


Solution

  • You are right, by creating object manually you are not letting Spring to perform autowiring. Consider managing your services by Spring as well:

    @Component
    public class MyServiceFactory {
    
        @Autowired
        private MyServiceOne myServiceOne;
    
        @Autowired
        private MyServiceTwo myServiceTwo;
    
        @Autowired
        private MyServiceThree myServiceThree;
    
        @Autowired
        private MyServiceDefault myServiceDefault;
    
        public static MyService getMyService(String service) {
            service = service.toLowerCase();
    
            if (service.equals("one")) {
                return myServiceOne;
            } else if (service.equals("two")) {
                return myServiceTwo;
            } else if (service.equals("three")) {
                return myServiceThree;
            } else {
                return myServiceDefault;
            }
        }
    }
    

    But I would consider the overall design to be rather poor. Wouldn't it better to have one general MyService implementation and pass one/two/three string as extra parameter to checkStatus()? What do you want to achieve?

    @Component
    public class MyServiceAdapter implements MyService {
    
        @Autowired
        private MyServiceOne myServiceOne;
    
        @Autowired
        private MyServiceTwo myServiceTwo;
    
        @Autowired
        private MyServiceThree myServiceThree;
    
        @Autowired
        private MyServiceDefault myServiceDefault;
    
        public boolean checkStatus(String service) {
            service = service.toLowerCase();
    
            if (service.equals("one")) {
                return myServiceOne.checkStatus();
            } else if (service.equals("two")) {
                return myServiceTwo.checkStatus();
            } else if (service.equals("three")) {
                return myServiceThree.checkStatus();
            } else {
                return myServiceDefault.checkStatus();
            }
        }
    }
    

    This is still poorly designed because adding new MyService implementation requires MyServiceAdapter modification as well (SRP violation). But this is actually a good starting point (hint: map and Strategy pattern).