Каковы основные принципы проектирования по шаблону внедрения зависимостей?

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

На вопросы:

  1. Скажем, у меня есть интерфейс для аппаратных устройств с именем IDevice. И некий слушатель HW, который получает такой IDevice. Теперь предположим, что у вас есть несколько аппаратных устройств, которые реализуют IDevice и несколько прослушивателей. Вам нужно указать для каждого слушателя, какое конкретное устройство нужно внедрить. Вы не можете просто сопоставить одно устройство с интерфейсом, вам нужно что-то вроде множественного сопоставления.

ну, одно из возможных решений - создать еще один уровень абстракции для каждого реального устройства, например

public interface IActualDevice : IDevice
{}

public ActualDevice : IActualDevice
{}

public SimulatedActualDevice : IActualDevice
{}

public OtherAcualDevice: IOtherAcualDevice
{}

тогда можно было бы создать такое отображение:

container.RegisterType<IActualDevice, ActualDevice>()

или если HW отсутствует:

container.RegisterType<IActualDevice, SimulatedActualDevice>()

так что вы говорите, что это хороший дизайн?

  1. Шаблон DI дает нам хороший механизм создания объектов.

Как насчет клея, как насчет подписки на события между объектами?

вам не кажется, что он отсутствует или, лучше, мне не хватает какой-то функции Unity, которая его поддерживает.

Адиэль.


person Adiel Yaacov    schedule 15.07.2010    source источник


Ответы (2)


Нет необходимости вводить интерфейсы маркеров, чтобы ваш DI-контейнер работал — это будет дырявая абстракция.

В Unity вы можете настроить каждый Listener с собственной реализацией IDevice следующим образом:

container.RegisterType<IDevice, ActualDevice>("actual");
container.RegisterType<IDevice, OtherActualDevice>("otherActual");

container.RegisterType<IListener, Listener1>("listener1",
    new InjectionConstructor(
        new ResolvedParameter<IDevice>("actual")));
container.RegisterType<IListener, Listener2>("listener2",
    new InjectionConstructor(
        new ResolvedParameter<IDevice>("otherActual")));

Теперь вы можете разрешать прослушиватели следующим образом:

var listener1 = container.Resolve<IListener>("listener1");
var listener2 = container.Resolve<IListener>("listener2");

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

person Mark Seemann    schedule 15.07.2010
comment
именно тот ответ, который я искал на первый вопрос. Я предложил абстракцию Leaky, зная, что она уродлива, просто для обсуждения, чтобы прояснить мою точку зрения. Что касается моего второго вопроса, я думаю о том, чтобы иметь AppFactory, который будет производить клей - все подписки на события между событиями. что ты говоришь ? - person Adiel Yaacov; 15.07.2010
comment
Вы можете просмотреть события домена: msdn.microsoft.com/en-us /магазин/ee236415.aspx - person Mark Seemann; 15.07.2010

1) Это совершенно плохая идея, потому что интерфейсы предназначены для того, чтобы скрывать детали реализации. Используйте тип IDevice везде и внедряйте эту зависимость вручную

IDevice d;

if(a == 1)
{
   d = container.Resolve<SimulatedActualDevice>()
}
else
{
   d = container.Resolve<ActualDevice>()
}

User user = container.Resolve<IUser>();
user.Device = d;

Если вы не хотите использовать имена классов реализации в коде, используйте именованные регистрации:

IDevice d;

if(a == 1)
{
   d = container.Resolve<IDevice>("Simulated")
}
else
{
   d = container.Resolve<IDevice>("Actual")
}

User user = container.Resolve<IUser>();
user.Device = d;

2) Подписка на события между объектами является частью инициализации объекта, но не частью создания. Unity просто инкапсулирует «новые» операторы. Делайте подписки в конструкторах или на специальных фабриках, как вы это делали до использования контейнера внедрения зависимостей.

person Yauheni Sivukha    schedule 15.07.2010
comment
-1 В этом ответе рекомендуются как Tight Coupling, так и анти-шаблон Service Locator — обе совершенно плохие идеи. - person Mark Seemann; 15.07.2010
comment
Tight Coupling используется только в качестве примера, и на самом деле это не такая уж плохая идея с паттерном Strategy. Что касается локатора сервисов - пожалуйста, предложите другой способ. Самый распространенный пример — Как динамически создавать объекты разных стратегий? - person Yauheni Sivukha; 15.07.2010
comment
Да и как вы будете реализовывать такую ​​абстрактную фабрику? Вручную создайте объект, как в stackoverflow.com/questions/1926826 /cant-combine-factory-di/? В этом случае ваша абстрактная фабрика будет иметь кучу ненужных зависимостей. Гораздо лучше использовать Tight Coupling и Service Locator при реализации этой фабрики. - person Yauheni Sivukha; 15.07.2010
comment
Смотрите мой комментарий к этому вопросу. - person Mark Seemann; 15.07.2010