Как спроектировать DI, где класс зависит от порядка создания экземпляра

Это кажется довольно стандартным вопросом, и, вероятно, его задавали раньше, но мне было трудно его найти, потому что его трудно определить словами. Так что, если это дубликат, перенаправьте меня!

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

У меня три класса:

  • Стол
  • ФильтрГенератор
  • Контейнер

Мой «дизайн» выглядит так:

  • Контейнер добавляет в свой конструктор некоторые свойства (заголовки столбцов).
  • FilterGenerator @Inject the Container (чтобы использовать метод getDistinct () контейнера, который получает отдельные элементы из контейнера - чтобы красиво представить их в ComboBox в фильтре) < / em>
  • Таблица @Inject the FilterGenerator (для table.setFilterGenerator (filterGenerator))
  • Таблица @Inject the Container и вызывает метод контейнеров addItems () для добавления элементов в контейнер.
  • Таблица затем добавляет контейнер в качестве источника данных.

Что происходит?

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

Я получаю таблицу с ComboBox в заголовке столбца, в которой ничего не представлено в ComboBox, потому что в ComboBox нет элементов.

Это неудивительно, потому что, когда FilterGenerator вызывает метод Containers getDistinct (), он возвращает пустую карту <Column, items>, потому что во время @Inject в FilterGenerator таблица не вызвала метод Containers addItems () , поэтому Контейнер в этот момент будет пустым.

Вопрос

Как мне разработать это приложение, если я хочу, чтобы компонент (FilterTable) получал что-то от второго компонента (Container), когда третий компонент (Table) - это @ Inject-ing обоих вышеупомянутых компонентов, и крайне важно, чтобы второй компонент (Контейнер) уже был инициализирован, когда первый компонент (FilterGenerator) что-то получает от него?

Я мог бы:

  • В таблице просто создайте new FilterGenerator. Это сработает, но это не очень хорошо. Например, что произойдет, если какой-то другой компонент захочет использовать FilterGenerator?

  • Вернитесь к xml-конфигурации, чтобы «вручную» создать экземпляры в правильном порядке. Это вероятно сработает (если я правильно помню), но создание экземпляра в зависимости от порядка элементов в вашем XML-файле мне не очень нравится.

  • Используйте «программную инъекцию», используя ApplicationContext.getBean () в коде. Это, наверное, было бы даже хуже, чем вышеперечисленные альтернативы?

Есть ли у кого-нибудь хорошие предложения, как разрешить эту треугольную драму?

Вот соответствующий код:

Стол

@Component
@Scope("session")
public class SampleAppMainTable extends FilteringTable {

    @Inject
    private SampleAppMainTableContainer sampleAppMainTableContainer;
    @Inject
    private SampleAppService sampleAppService;
    @Inject
    private SampleAppMainTableFilterGenerator sampleAppMainTableFilterGenerator;

    public SampleAppMainTable() {
        //...setting up the table
    }

    @PostConstruct
    public void PostConstruct() throws GeneralSecurityException {
        addMainTableItems();
        setupMainTable();
    }

    public void setupMainTable() {
        this.setFilterGenerator(sampleAppMainTableFilterGenerator);
        sampleAppMainTableFilterGenerator.getCustomFilterComponent("Sample Id");
        this.setContainerDataSource(sampleAppMainTableContainer);
    }

    public void addMainTableItems() {
            sampleAppMainTableContainer.addItemsToContainer(sampleAppService.getAllSamples());
    }
}

Контейнер

@Component
@Scope("prototype")
public class SampleAppMainTableContainer extends IndexedContainer {

    public void addItemsToContainer(List<Sample> samples) {
        // adding items to the container...
    }

    public Map<String, List<String>> getDistinctProperties() {
        // extracting distinct items from the table...
    }
}

Генератор фильтров

@Component
@Scope("session")
public class SampleAppMainTableFilterGenerator implements FilterGenerator {

    @Inject
    SampleAppMainTableContainer sampleAppMainTableContainer;

    private List<String> aList = null;

    @Override
    public AbstractField<?> getCustomFilterComponent(Object propertyId) {

        Map<String, List<String>> map = new HashMap<String, List<String>>();

        map = sampleAppMainTableContainer.getDistinctProperties();

        if (propertyId.equals("Sample Id")) {
            ComboBox sampleIdCB = new ComboBox();
            BeanItemContainer<String> dataList = new BeanItemContainer<String>(String.class);
            List<String> aList = map.get("Sample Id");
            dataList.addAll(aList);
            sampleIdCB.setContainerDataSource(dataList);
            sampleIdCB.setImmediate(true);
            return sampleIdCB;
        }

        return null;
    }

    // other overridden methods needed...
}

person Roger    schedule 27.09.2013    source источник
comment
Разве ваша проблема не в том, что ваш FilterGenerator имеет состояние, тогда как он должен быть без состояния?   -  person M. Deinum    schedule 27.09.2013
comment
Спасибо за ваш ответ! Я не совсем понимаю, что вы имеете в виду под безгражданством. Мой класс FilterGenerator - это простой класс, который реализует (надстройку Vaadin) FilterGenerator. Что он делает, так это @Override несколько методов, которые генерируют желаемые фильтры, которые будут использоваться в моей таблице. Моя проблема связана с тем, что контейнер не полностью инициализирован при создании FilterGenerator. Если я создам new FilterGenerator(container) в классе Table, все будет работать как шарм.   -  person Roger    schedule 27.09.2013
comment
Мне трудно понять вашу настройку из вашего описания. Можете ли вы предоставить несколько фрагментов кода, которые показывают, что вы делаете и где?   -  person Sven Amann    schedule 27.09.2013
comment
Я не знаком с Vaadin, но из вашего описания похоже, что вы создаете фильтр, который удерживает состояние (он вызывает определенный метод один раз и кэширует результаты), тогда как, я думаю, он всегда должен вызывать метод при необходимости.   -  person M. Deinum    schedule 27.09.2013
comment
Вы сами реализовали фильтр? Вы говорите только о FilterGenerator ... Вы уверены, что один и тот же экземпляр-контейнер вводится оба раза? В зависимости от используемой Inject-Framework вам необходимо явно указать, будет ли создаваться новый экземпляр для каждой инъекции или будет использоваться синглтон.   -  person Sven Amann    schedule 27.09.2013


Ответы (1)


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

person Sven Amann    schedule 27.09.2013