Создание подключаемого StrategyFactory с DI

У меня есть движок, который создает стратегии для обработки текстовых файлов. Эти файлы имеют различные форматы, и механизм выбирает подходящую стратегию, передавая файл через цепочку стратегий, пока одна из них не подтвердит, что может его проанализировать.

Это не совсем классическая стратегия. Он чем-то похож на шаблон локатора службы и шаблоны цепочки ответственности и может включать в себя аспекты любого из них.

В разобранном виде это выглядит примерно так, хотя в настоящее время оно создается с помощью инъекций:

        public class EngineImpl {

            private Set<Strat> strategies = new HashSet<Strat>();

            public EngineImpl(){
                registerStrategy(new ConcreteStrat1());
                registerStrategy(new ConcreteStrat2());
            }

            public void registerStrategy(Strat strat){
                strategies.add(strat);
            }

            public Strat getStrategy(SomeClass input){
                for (Strat s: strategies)
                    if (s.canParse(input)
                         return s;
                return null;
            }

        }

В настоящее время проблема заключается в том, что EngineImpl должен знать все доступные стратегии во время компиляции, чтобы это работало, и я хотел бы иметь возможность развертывать новые стратегии без изменения кода EngineImpl. В других местах я искал варианты сделать это на Java и придумать пробелы. Я подумал о том, чтобы классы Strat регистрировались в Engine, но они никогда не загружались загрузчиком классов, и поэтому у меня никогда не было возможности зарегистрироваться.

Какие альтернативные методы я могу использовать для регистрации стратегий? Хотя в настоящее время я использую DI, я открыт для других решений на основе рефлексии и / или аннотаций.

1 ответ

Итак, на данный момент, я думаю, что я собираюсь сделать следующее, которое хотя и далеко от идеала, по крайней мере связывает это с остальной частью моего управления зависимостями.

добавить метод init в интерфейс Strat (реализации должны регистрироваться сами);

public void init(Engine e);

создайте и внедрите каждый слой в мой GuiceModule, который создает синглтон и вызывает внедренный метод.

bind(ConcreteStrat1.class).asEagerSingleton();

Есть проблемы с этим подходом, которые, я надеюсь, могут быть решены. Объекты Strat должны аннотировать свой метод init с помощью @Inject, иначе он никогда не будет вызван. Eclipse старательно копирует это, когда вставляет заглушки метода, но, насколько я могу судить, это невозможно. Я не уверен, как это будет работать со стратегиями "вбрасывания", но, думаю, в отсутствие чего-либо лучшего я перейду этот мост позже.

eta: сейчас я пишу стратегии javascript, которые можно загружать из базы данных, что делает его легко подключаемым с помощью JavascriptStrategyManager