Какова наилучшая стратегия для внедрения зависимостей пользовательского ввода?

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

У меня есть класс, который подключается к com-порту. Я разрешаю пользователю выбирать номер COM-порта. Прямо сейчас у меня есть этот параметр com-порта в качестве аргумента конструктора. Причина в том, что класс не может функционировать без этой информации и зависит от реализации (фиктивной версии этого класса не нужен com-порт).

В качестве альтернативы можно использовать метод «Пуск», который принимает com-порт, или иметь свойство, которое устанавливает com-порт. Это делает его очень совместимым с контейнером IoC, но это не обязательно имеет смысл с точки зрения класса.

Кажется, что логический маршрут конфликтует с дизайном внедрения зависимостей, но это потому, что мой пользовательский интерфейс получает информацию для определенного типа класса.

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

Существует ли общепринятый стандартный шаблон для такого типа задач?


person Jason Young    schedule 05.11.2009    source источник


Ответы (2)


Есть два пути, по которым вы можете пойти, в зависимости от ваших потребностей.

1. Подключите пользовательский интерфейс напрямую к вашим конкретным классам

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

Положительным моментом является то, что этот подход прост и легок для понимания и реализации.

Недостатком является то, что вы получаете меньше гибкости. Вы не сможете произвольно заменить одну реализацию другой (но опять же, вам может не понадобиться эта гибкость).

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

2. Добавьте абстрактную фабрику

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

Фабричный метод Create может принимать номер порта в качестве входных данных, поэтому эта абстракция лучше всего подходит для подуровня пользовательского интерфейса.

public abstract class MyFactory
{
    public abstract IMyInterface Create(int portNumber);
}

Затем вы можете подключить контейнер DI к реализации этой фабрики, которая использует номер порта и передает его в качестве аргумента конструктора вашей реальной реализации. Другие фабричные реализации могут просто игнорировать этот параметр.

Преимущество этого подхода заключается в том, что вы не загрязняете свой API (или ваши конкретные реализации) и по-прежнему сохраняете гибкость, которую дает вам программирование для интерфейсов.

Недостатком является то, что он добавляет еще один уровень косвенности.

person Mark Seemann    schedule 06.11.2009

Большинство контейнеров IoC имеют ту или иную форму внедрения конструктора, которая позволяет вашему IoC container для передачи фиктивного COM-порта в ваш класс для модульного тестирования. Это кажется самым чистым решением.

Я бы не стал добавлять метод «Пуск» и т. д. Гораздо лучше (когда это возможно) всегда иметь ваши классы в допустимом состоянии, а переключение на конструктор без параметров с методом запуска оставляет ваш класс недействительным между этими вызовами. Делая это, чтобы включить тестирование, вы просто усложняете свой класс для тестирования (что должно сделать его лучше).

person Reed Copsey    schedule 05.11.2009
comment
Извините, я должен был быть более ясным. COM-порт - это просто номер. Тестирование не проблема, так как я могу создать фиктивную версию класса. Компорт заранее не знаю, узнаю от пользователя. В этом случае кажется глупым, чтобы пользовательский интерфейс использовал интерфейс, поскольку для этого нужна реализация, для которой нужен com-порт. - person Jason Young; 05.11.2009