IoC: как создавать объекты динамически
-
03-07-2019 - |
Вопрос
У меня проблема с пониманием того, как использовать 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 Entites:
class EntityA {
public EntityA( IFieldFactory fieldFactory ) {
// create as many fields as needed via the factory
Fields.Add( fieldFactory.CreateStringField() );
}
}
По крайней мере (для Entity) ненужного ICommandStack теперь нет. Но как FieldFactory создает поле? Он может только внедрить ICommandStack, но создание полей все еще должно выполняться с помощью ключевого слова «new». Или я должен дать фабрике ссылку на мой DI-контейнер?
Что такое хорошее дизайнерское решение здесь?
Решение
Я бы использовал FieldFactory и внедрил бы фабрику со ссылкой на контейнер (или на интерфейс, который абстрагирует его, если вы недовольны сильной зависимостью от вашего контейнера).
В противном случае, это черепахи вниз. Вам нужен какой-то объект, чтобы запросить у контейнера новый экземпляр в какой-то момент. Если вы хотите, чтобы ваши поля вводились с помощью DI, вам нужно попросить контейнер создать их или вас. Р>
Подводя итог, я бы пошел с завода.
Другие советы
В Spring (и Spring.NET) существует концепция " области прототипа " бобы / объект. Р>
Вместо того, чтобы вставлять фиксированные объекты и соединять их все вместе, область действия прототипа будет создавать новый экземпляр объекта каждый раз, когда его запрашивают из контейнера IoC. Я не уверен, какой DI-фреймворк вы используете, но он может иметь что-то похожее.