2013-09-06 9 views
9

99% mojej zależności jest zarządzana za pomocą wzoru DI za pomocą adnotacji @Autowired Spring.Spring ServiceLocator lub czysty wzór fabryczny?

Mimo to w konkretnym scenariuszu nie mogę określić, której implementacji należy użyć do czasu wykonania.

Najbardziej znanym przypadkiem jest wielokrotna implementacja analizatorów składni.

Pierwsze rozwiązanie jest stosowane w trybie wielokrotnego @Autowired (brzydki)

Interface Parser { 
    <T> T parse(); 
} 

@Component("JsonParser") 
class JsonParser implements Parser { 
    ... 
} 

@Component("XmlParser") 
class XmlParser implements Parser { 
    ... 
} 

class MyService { 
    @Autowired 
    @Qualifier("XmlParser") 
    Parser xmlParser; 

    @Autowired 
    @Qualifier("JsonParser") 
    Parser jsonParser; 

    ...  
} 

Ale jeżeli mam dużą liczbę realizacji, które mogą być nie do zaakceptowania.

Drugie rozwiązanie jest stosowane ServiceLocator od wiosny

interface ParserServiceLocatorFactory { 
    public Parser getParser(String parserName); 
} 

interface Parser { 
    <T> T parse(); 
} 

@Component("JsonParser") 
class JsonParser implements Parser { 
    ... 
} 

@Component("XmlParser") 
class XmlParser implements Parser { 
    ... 
} 

class MyService { 
    @Autowired 
    ServiceFactory parserServiceLocatorFactory; 

    void exampleMethod() { 
     Parser xmlParser = parserServiceLocatorFactory.getParser("XmlParser"); 
    } 
} 

ten sposób to zrobić wydaje mi rację, ale w porównaniu z trzecim rozwiązania?

Trzecie rozwiązanie polega na użyciu czysto fabrycznego wzoru i wstrzyknięciu go.

@Component 
public ParserFactory { 
    Parser getParser(String parserName) { 
     ... 
    } 
} 

interface Parser { 
    <T> T parse(); 
} 

@Component("JsonParser") 
class JsonParser implements Parser { 
    ... 
} 

@Component("XmlParser") 
class XmlParser implements Parser { 
    ... 
} 

class MyService { 
    @Autowired 
    ParserFactory parserFactory 

    void exampleMethod() { 
     Parser xmlParser = parserFactory.getParser("XmlParser"); 
    } 
} 

Jeśli masz pro/con do poprzednich rozwiązań, albo nawet lepszym rozwiązaniem dla mojego problemu?

PS: to pseudo kod może tęsknię kilka małych rzeczy :)

Odpowiedz

8

Opcjonalnie można użyć listy wtrysku:

public class SomeService { 

    @Autowired 
    private List<Parser> parsers; 

    public doSomethingWithParser(...) { 
     ... 
     Parser parser = getParser(JsonParser.class); 
     parser.parse(...); 
     ... 
    } 

    private Parser getParser(Class<Parser> targetClass) { 
     Parser result = null; 
     for(Parser parser : parsers) { 
      if(parser.getClass().equals(targetClass)){ 
       result = parser; 
      } 
     } 
     return transformer; 
    } 

} 

Nawet lepiej, można dodać Parser.isCompatibleWith(SomeInput input) metody uproszczenia paser kod wykrywania .

+0

Czy można @Autowiować listę? Wiem, że jest to możliwe przy użyciu XML, ale nigdy nie słyszałem o adnotacji. Czy masz jakieś linki do dokumentów? – Kakawait

+1

Tak, jest to możliwe. Używam tego podejścia w moim obecnym projekcie. [Przejdź do przykładowego zbioru kolekcji] (http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-autowired-annotation). –

+0

Niewielką modyfikacją sugerowanego powyżej podejścia będzie użycie kolekcji typów analizatorów MAP. W ten sposób możesz wykonać wyszukiwanie w stałym czasie, używając klawisza mapy, który jest nazwą typu. Uniknie pętli FOR za każdym razem, gdy chcesz wyszukać usługę analizatora składni. – Kingz

5

Poniżej znajduje się przykład klasy lokalizatora usług. Zwraca usługę dla danego identyfikatora z rejestru usług. Rejestr jest MAP, który jest autowired jak pokazano. To jest działający przykład z systemu produkcyjnego:

@Service 
public class MyServiceLocator { 

    @Autowired 
    private Map<String, MyService> myServiceRegistry; 

    /** 
    * Service locator to find the right Domain service to interact with the  requested data store 
    * 
    * @param serviceID 
    * @return 
    */ 
    public MyService locateServiceFor(String serviceID) { 
     //Using the Given string 'serviceID' as key, lookup the service from the Registry 
     return myServiceRegistry.get(serviceID); 
}