Я запутался в абстракциях интерфейса при использовании IoC
Недавно я пытался изучить IoC и задать пару вопросов на основе следующего кода:
public class WarriorModule : NinjectModule
{
public override void Load()
{
Bind<IWeapon>().To<Sword>();
Bind<Samurai>().ToSelf();
}
}
У меня возникли проблемы с пониманием новой концепции интерфейсов. Прежде чем я создам интерфейс, такой как IRunnable
, реализующий функцию void Run()
. С IoC я теперь просматриваю интерфейс как что-то, что только сопоставляется с одним конкретным классом. Предполагая, что как я могу сопоставить несколько конкретных классов с интерфейсом? Я продолжаю читать, что вы можете сопоставить несколько интерфейсов с одним конкретным классом, но не наоборот (если это не значит, что контекстное отображение в игру).
Предполагая, что интерфейсы относятся только к одному объекту, , когда мне нужно создать интерфейс, а не привязывать объект к себе? В любом случае вам придется изменить один и тот же фрагмент кода при сопоставлении изменения правильные?
Изменить: я отметил ответ, который я сделал, потому что это помогло мне лично. Оба комментария одинаково информативны, хотя.
Ответы
Ответ 1
Недавно я обратился к этой теме с более общей точки зрения. Суть в том, что существует тенденция к слабо связанному коду для создания переизбытка интерфейсов 1:1. Это противоречит принципу Reused Abstractions.
Однако это больше проблема , чем проблема с конкретными контейнерами DI. Хотя я не знаю Ninject, все другие контейнеры, с которыми я когда-либо работал (Castle Windsor, StructureMap, Spring.NET, Autofac, Unity и даже MEF) могут сопоставлять несколько реализаций с одним и тем же интерфейсом. Как они немного отличаются друг от друга, но я охватываю их в IV части моей книги - к сожалению, Ninject не рассматривается в книге.
Ответ 2
Хороший контейнер IoC не должен изменять способ использования интерфейсов:
- Интерфейс должен быть разработан для компонента, который использует его как зависимость, а не класса, который его реализует. (принцип сегрегации интерфейса)
- Класс может реализовывать несколько интерфейсов. Но это нужно делать только в том случае, если эти интерфейсы предназначены для одного и того же типа услуг, чтобы класс выполнял именно одну вещь. Если интерфейсы предназначены для двух разных вещей, они должны быть реализованы двумя разными классами. (принцип единой ответственности)
- Несколько классов могут реализовать один и тот же интерфейс, если вам нужны несколько стратегий для этого типа услуг.
Ninject позволяет использовать интерфейсы таким образом, используя две разные концепции:
-
Условные привязки: если несколько классов реализуют один и тот же интерфейс, вы должны указать, какая реализация используется в этом случае. Это делается с использованием условий:
Bind<IWeapon>().To<Sword>().When(ctx => TodayIsSunday());
Bind<IWeapon>().To<Dagger>().When(ctx => !TodayIsSunday());
-
Несколько интерфейсов: см. мой блогпост http://www.planetgeek.ch/2010/12/08/ninject-extension-contextpreservation-explained/