IoC: как динамически создавать объекты

У меня проблема с пониманием того, как использовать IoC в сценарии, где мне нужно динамически создавать объекты. Предположим, у меня есть эти классы:

abstract class Field {
  public Field( ICommandStack commandStack ) {}
}

abstract class Entity {
  public readonly Collection<Field> Fields { get; }
}

class EntityA {
  public EntityA( ICommandStack commandStack ) {
    Fields.Add( new StringField( commandStack ) );
  }
}

class EntitiyB {
  public EntityB( ICommandStack commandStack ) {
    Fields.Add( new IntField( commandStack ) );
    Fields.Add( new IntField( commandStack ) );
    Fields.Add( new IntField( commandStack ) );
  }
}

Итак, моя проблема заключается в создании полей в конструкторах. Моим полям нужен ICommandStack, а объектам — нет. Они получают ICommandStack только для создания своих полей.

Было бы проще запросить поля в качестве аргумента в конструкторе каждой сущности. Но количество полей может быть > 10 для отдельных сущностей. Я не хочу создавать конструкторы с таким количеством параметров.

Итак, моя идея состояла в том, чтобы передать FieldFactory энтитам:

class EntityA {
  public EntityA( IFieldFactory fieldFactory ) {
    // create as many fields as needed via the factory
    Fields.Add( fieldFactory.CreateStringField() );
  }
}

По крайней мере, ненужного (для Entity) ICommandStack больше нет. Но как FieldFactory создает поле? Он может только ввести ICommandStack, но создание полей все еще должно быть выполнено с помощью ключевого слова «новое». Или я должен дать фабрике ссылку на мой DI-контейнер?

Какое здесь удачное дизайнерское решение?


person tanascius    schedule 04.05.2009    source источник


Ответы (2)


Я бы использовал FieldFactory и внедрил бы factory со ссылкой на контейнер (или на интерфейс, который абстрагирует его, если вас не устраивает сильная зависимость от вашего контейнера).

В противном случае, это черепахи полностью вниз. Вам нужен какой-то объект, чтобы в какой-то момент запросить у контейнера новый экземпляр. Если вы хотите, чтобы ваши поля были DI-инжектированы, вам нужно попросить контейнер построить их или вас.

Подводя итог, я бы выбрал завод.

person Denis Troller    schedule 04.05.2009

В Spring (и Spring.NET) существует концепция bean-компонента/объекта с областью действия прототипа.

http://static.springframework.org/spring/docs/2.0.x/reference/beans.html#beans-factory-scopes-prototype

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

person Andy White    schedule 04.05.2009
comment
Но где и как я могу запросить? FieldFactory по-прежнему нужна ссылка на контейнер для запроса объектов. - person tanascius; 04.05.2009