Это довольно простой сценарий шаблона декоратора, с усложнением, что декорированный тип имеет параметр конструктора, который зависит от типа, в который он внедряется.
У меня есть такой интерфейс:
interface IThing
{
void Do();
}
И реализация, подобная этой:
class RealThing : IThing
{
public RealThing(string configuration)
{
... implementation ...
}
public void Do()
{
... implementation ...
}
}
И декоратор, как это:
class DecoratingThing : IThing
{
IThing _innerThing;
public DecoratingThing(IThing thing)
{
_innerThing = thing;
}
public void Do()
{
_innerThing.Do();
}
}
Наконец, у меня есть некоторые типы, которые требуют IThing
, называется Depender1
, Depender2
и т. д.
class DependerX()
{
public DependerX(IThing thing)
{
... implementation ...
}
}
Я хочу настроить контейнер IOC для разрешения экземпляров DependerX
таким образом, чтобы они вводились с помощью RealThing
, украшенным DecoratingThing
. Важно: Каждый DependerX
тип требует, чтобы в конструктор его RealThing
передавалось различное значение configuration
, скажем «ConfigX» в каждом случае.Например, работа, выполняемая контейнером IoC, может быть такой:
new Depender1(new DecoratingThing(new RealThing("Config1")));
new Depender2(new DecoratingThing(new RealThing("Config2")));
... и т. д.
В Unity это выглядит довольно неуклюже для настройки, так как мне приходится смешивать в декораторес декорированным:
container.RegisterType<IThing, DecoratingThing>("ConfigX",
new InjectionFactory(container => new DecoratingThing(new RealThing("ConfigX"));
container.RegisterType<DependerX>(
new InjectionConstructor(new ResolvedParameter<IThing>("ConfigX");
И повторяю, красиво нарушая DRY, для каждого DependerX
.
Что я хотел бы сделать, так это убрать необходимость встраивания конструкции RealThing
в конструкции DecoratingThing
в каждой именованной регистрации IThing
- и объявлять украшение только один раз.Это так, например, что если в будущем необходимо изменить оформление, его проще перенастроить.Лучшее, что я придумал, - это вспомогательный метод для регистрации:
void RegisterDepender<TDepender>(IUnityContainer container, string config)
{
container.RegisterType<TDepender>(new InjectionConstructor(
new ResolvedParameter<IThing>(config)));
container.RegisterType<IThing, DecoratingThing>(config,
new InjectionFactory(c => new DecoratingThing(new RealThing(config))));
}
Это, по крайней мере, удаляет повторение, но мне все еще нужно встроить конструкцию RealThing
в DecoratingThing
- это означает, что янапример, не могут изменить время жизни независимо друг от друга.Я не могу зарегистрироваться IThing
снова, чтобы сделать это, потому что я использовал мою регистрацию этого интерфейса для имени.Если я хочу сделать это, я должен представить другой набор именованных экземпляров, например, так:
void RegisterDepender<TDepender>(IUnityContainer container, string config)
{
string realConfig = "Real" + config;
container.RegisterType<TDepender>(new InjectionConstructor(
new ResolvedParameter<IThing>(config)));
container.RegisterType<IThing, DecoratingThing>(config,
new InjectionFactory(c => new DecoratingThing(
container.Resolve<IThing>(realConfig))));
container.RegisterType<IThing, RealThing>(realConfig,
new ContainerControlledLifetimeManager(),
new InjectionConstructor(config));
}
Является ли этот действительно лучшим вариантом?Это чувствует себя сложным и потенциально трудным для тех, кто придет после укуса.У других контейнеров IoC есть убедительный способ покрыть этот сценарий?Поскольку шаблон для того, как работает внедрение, повторяется для каждого DependerX, есть ли способ использовать только именованный экземпляр на верхнем (DependerX
) уровне?
Любые другие комментарии?