13

私の依存関係の 99% は、@Autowired Spring アノテーションを介した DI パターンで管理されています。

それにもかかわらず、特定のシナリオでは、実行時までどの実装を使用するかを決定できません。

最もよく知られているケースは、パーサーの複数の実装です。

最初の解決策は、複数の @Autowired (醜いモード) を使用することです。

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;

    ...     
}

しかし、受け入れられない実装が多数ある場合。

2 番目の解決策は、Spring の ServiceLocator を使用することです。

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");
    }
}

この方法は私には正しいように思えますが、3番目のソリューションと比較して?

3 番目の解決策は、純粋なファクトリ パターンを使用して注入することです。

@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");
    }
}

以前の解決策に賛否両論がある場合、または私の問題に対するより良い解決策がある場合は?

PS:これは疑似コードなので、小さなことを見逃す可能性があります:)

4

2 に答える 2

11

オプションとして、リスト インジェクションを使用できます。

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;
    }

}

さらに良いことに、Parser.isCompatibleWith(SomeInput input)メソッドを追加して、ペイサー検出コードを簡素化できます。

于 2013-09-06T10:31:55.177 に答える
8

以下は、サービス ロケーター クラスの例です。これは、サービス レジストリから指定された ID のサービスを返します。レジストリは、示されているように自動配線される MAP です。これは、実動システムでの実際の例です:

@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);
}
于 2014-01-29T19:29:36.780 に答える