DI, factory, или новый для эфемерных объектов?
При работе с объектами, для которых требуются данные, известные только во время выполнения, такие как имя пользователя и пароль, где должно происходить создание экземпляра объекта: с помощью нового, в factory или в контейнере DI?
Например, я мог бы просто new
объект, когда у меня есть данные:
UserCredentials creds =
new UserCredentials(dialog.getUsername(), dialog.getPassword());
Или, я мог бы использовать factory:
UserCredentials creds =
CredentialsFactory.create(dialog.getUsername(), dialog.getPassword());
Или я мог бы использовать поставщика в контейнере DI (который в этом случае будет по существу управляться параметрами factory). [Пример кода опущен.]
Кажется, что неправильно использовать контейнер DI для чего-то настолько простого, но также кажется неправильным не использовать его в полной мере.
Ответы
Ответ 1
Как всегда, это зависит, но, как правило, статический factory, как и ваш второй вариант, редко бывает хорошей идеей.
new
Включение объекта UserCredential представляется справедливым выбором, потому что класс UserCredentials выглядит как автономный конкретный класс, который может быть полностью инстанцирован со всеми его инвариантами от имени пользователя и пароля.
В других случаях тип, который вы хотите создать, может представлять собой абстракцию сам по себе. Если это так, вы не можете использовать ключевое слово new
, но вместо этого должны использовать Абстрактные Factory.
Использование абстрактного factory часто очень ценно, потому что оно позволяет вам составлять экземпляр из комбинации значений времени выполнения и других зависимостей. Подробнее см. здесь.
Использование абстрактного factory также помогает при модульном тестировании, потому что вы можете просто проверить, что возвращаемое значение или конечное состояние или все, что вам нужно, связано с выходом Abstract factory - для которого вы можете легко предоставить Test Double, потому что это... abstract.
Ответ 2
В блоге тестирования google есть сообщение, которое пытается ответить на этот вопрос. Основная идея заключается в том, что вы можете классифицировать каждый из ваших классов как "новаторский" или "инъецируемый", и что это нормально, чтобы просто "обновлять" новые.
Я различаю две основные категории "newables":
- значения, такие как
int
, string
, DateTime
и т.д.
- объекты, такие как
Customer
, Order
, Employee
и т.д. Я думаю, что ваш класс UserCredentials
попадает под этот заголовок.
Важно понимать, что newables может иметь (проверяемое) поведение. Если вы допустили ошибку, считая, что новые элементы не должны иметь никакого поведения или модульных тестов, вы получите модель анемичного домена anti -pattern.
Побочным эффектом наличия "новых возможностей" в поведении является то, что это поведение не может быть абстрагировано в модульных тестах ваших инъекционных препаратов. Хорошо; нормально иметь сильную связь между вашей моделью домена и остальной частью вашего приложения.
Кроме того, новизнам разрешено знать о инъекциях, но они лишь временно сотрудничают с ними. Например, UserCredentials
не должен принимать IUserDatabase
в качестве аргумента конструктора. Вместо этого может быть метод UserCredentials.Verify(IUserDatabase)
.
edit: Я сейчас не так уверен в том, что написал выше. Объекты также могут быть построены с помощью (инъектируемых) фабрик, а не напрямую ссылаться на их конструктор. Реализация factory может затем вставлять вещи в объект.
Ответ 3
Для меня я использую DI для создания более свободной связи между объектами. Если ваши объектные зависимости сильно влияют на создание объекта с использованием нового, то я не понимаю, почему вы не могли использовать создание объектов DI или ретрансляции объекта factory. Это дает вам больше контроля и поддерживает ваши классы loosley.
Это действительно зависит от того, когда и где вам понадобится этот объект, и если в результате возникнут ненужные зависимости.
Ответ 4
Если у вас уже установлен контейнер DI для вашего приложения, используйте этот подход. Если нет, используйте метод factory.