Jest to dość prosty scenariusz z wzorami dekoracyjnymi, z komplikacją, że dekorowany typ ma parametr konstruktora, który zależy od typu, w który jest wstrzykiwany.Konfigurowanie Unity w celu rozwiązania typu, który ma udekorowaną zależność, która ma parametr zmieniający się w zależności od typu, w który jest wstrzykiwany.
Mam interfejs tak:
interface IThing
{
void Do();
}
i wdrożenie takiego:
class RealThing : IThing
{
public RealThing(string configuration)
{
... implementation ...
}
public void Do()
{
... implementation ...
}
}
oraz dekoratora takiego:
class DecoratingThing : IThing
{
IThing _innerThing;
public DecoratingThing(IThing thing)
{
_innerThing = thing;
}
public void Do()
{
_innerThing.Do();
}
}
Wreszcie, mam kilka typów które wymagają IThing
, o nazwie Depender1
, Depender2
itd ..
class DependerX()
{
public DependerX(IThing thing)
{
... implementation ...
}
}
Chcę skonfigurować kontenera IOC rozwiązywać przypadki DependerX
taki sposób, że są one wstrzyknięto RealThing
ozdobione DecoratingThing
. Ważne: Każdy typ DependerX
typu wymaga podania innej wartości configuration
do konstruktora jej RealThing
, powiedzmy "ConfigX" w każdym przypadku. na przykład Praca wykonana przez kontener IoC może być:
new Depender1(new DecoratingThing(new RealThing("Config1")));
new Depender2(new DecoratingThing(new RealThing("Config2")));
... i tak dalej.
w jedności, to wydaje się dość niezgrabne skonfigurować jako muszę mieszać w dekoratora z zdobione:
container.RegisterType<IThing, DecoratingThing>("ConfigX",
new InjectionFactory(container => new DecoratingThing(new RealThing("ConfigX"));
container.RegisterType<DependerX>(
new InjectionConstructor(new ResolvedParameter<IThing>("ConfigX");
I powtarzam, naruszenie DRY przyjemnie, dla każdego DependerX
.
Co chcę zrobić, to usunąć potrzebę wbudowania konstrukcji RealThing
w konstrukcji DecoratingThing
w każdej wymienionej rejestracji IThing
- i zadeklarować dekorację tylko raz. Dzieje się tak, na przykład, jeśli dekoracja musi się zmienić w przyszłości, łatwiej jest zmienić konfigurację. Najlepszym wymyśliłem jest ta metoda pomocnika do rejestracji:
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))));
}
Usuwa powtórzenie co najmniej, ale wciąż muszę umieścić budowę RealThing
wewnątrz DecoratingThing
- oznacza to, że nie można zmieniać ich żywotność niezależnie na przykład. Nie mogę ponownie zarejestrować IThing
, ponieważ wykorzystałem moją rejestrację tego interfejsu dla nazwy. Jeśli chcę, aby to zrobić muszę wprowadzić inny zestaw nazwanych wystąpień tak:
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));
}
Czy to naprawdę najlepszym rozwiązaniem? Wydaje się to skomplikowane i potencjalnie trudne dla tych, którzy przyjdą po grzebaniu. Czy inne kontenery IoC mają nieodparty sposób na pokrycie tego scenariusza? Ponieważ wzorzec działania wtrysku jest powtarzany dla każdego DependerX, czy istnieje sposób użycia tylko nazwanej instancji na najwyższym poziomie (DependerX
)?
Jakieś inne komentarze?
Dzięki Mark. Sądzę, że podejście oparte na konwencjach jest sposobem na zastosowanie w moim konkretnym scenariuszu. Nie oznacza to, że inne podejścia (takie jak powyższy pomysł przechwytywania) nie są jednakowe. Miło słyszeć, że nie jestem tu na uboczu! –