230 likes | 390 Views
ZTO DI. Krzysztof Manuszewski. Kontenery DI. Kod prehistoryczny. Ograniczenia : Żeby zmienić klasy usług lub zmodyfikować zależności należy zmienić kod klasy zależnej Konkretna implementacja klas usługowych musi być dostępna w czasie kompilacji
E N D
ZTODI Krzysztof Manuszewski
Kod prehistoryczny Ograniczenia: • Żeby zmienić klasy usług lub zmodyfikować zależności należy zmienić kod klasy zależnej • Konkretna implementacja klas usługowych musi być dostępna w czasie kompilacji • Testowanie (jednostkowe?) klas jest trudne z powodu konieczności uwazględniania pot. Skomplikowanego zachowania klas usługowych • Klasy zawierają zduplikowany kod do tworzenia i zarzadzania serwisami.
DIprzypadekużycia public interface IService { } public class Application { private readonlyIService service; public Application(IService service) { this.service = service; } } public class ServiceImpl : IService { } Application a = new Application(new ServiceImpl()); //Co z ew. parametramiServiceImpl ?
IoC – z kontenerem DI IUnityContainer container = new UnityContainer(); //configuration UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); section.Containers.Default.Configure(container); … Application application = container.Resolve<Application>();
IoC - Przeglądrozwiązań • Castle • Unity • Ninject • Autofac • StructureMap • Spring.Net
DIC - Możliwościiróżnice: • Różnemodeleżyciaobiektów • Automatycznarejestracjaklas/obiektów (npprzezrefleksję) • Konfiguracja xml/programowa/skryptowa • Introspekcja • Kaskadowerozwiązywaniezależności • Wstrzykiwaniezależnościprzezkonstruktor/właściwości • Komunikowaniebłedów (npzależnościrekursywne, brakrozwiązaniadlatypu) • Obsługaniezwiązanychgeneryków, list obiektów
ServiceLocator UnityContainer container= new UnityContainer() ServiceLocator.SetLocatorProvider( () => new UnityServiceLocator(container) ); // container configuration container.configure….. ServiceLocator.Current.GetInstance<ILoger>() ServiceLocator.Current.GetInstance<IPresenter>("simple")
Życie jest skomplikowane... ServiceLocator UNITY Adapter GetInstance ModułA ModułC ModułB Konfiguracja
Unity Wstrzykiwanie zależności: • konstruktor • właściwości • metody Konfiguracja • Atrybuty • XML config • Programowa • Auto Registration Cykliczne referencje są raportowane jako Stack overflow ...
Prosty kod public interface IService { … }; public interface ILogger { … }; public class ConsoleLogger{ public ConsoleLogger() { … } } public class SimpleService { public SimpleService(ILogger logger) { … } } public class Application { public Application(ILogger logger, IService service) { … } }
Unity – konfiguracja programowa using (IUnityContainer container = new UnityContainer()) { container.RegisterType< IService, ServiceImpl>() .RegisterInstance< ILogger >(new ConsoleLogger ()); Application application = container.Resolve<Application>(); ILogger loggerInstance = container.Resolve<ILogger>(); }
Unity – konfiguracja xml using (IUnityContainer container = new UnityContainer()) { UnityConfigurationSection config = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); if (config != null) config.Containers.Default.Configure(container); Application application = container.Resolve<Application>(); }
Unity – XML elementy konfiguracji <unity> <typeAliases> <typeAlias alias="string" type="System.String, mscorlib" /> <typeAlias <typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </typeAliases> <containers> <container> <types> …. </types> </container> </containers> </unity> Aliases are not obligatory <type type="ILogger“ mapTo="ConsoleLogger”> <lifetime type="singleton"/> </type> <type type="IService“ mapTo="SimpleService"/> Mappings
Unity – wielokrotne konstruktory public class SimpleService : IService { public SimpleService(ILogger logger) { … } public SimpleService(String logFile) { … } } Unity domyślnie wybiera konstruktor z największa liczbą parametrów Jeżeli jest takich kilka rzucany jest wyjatek Jak określić który konstruktor ma być wybierany?
Unity – wybór konstruktora public class SimpleService : IService { [InjectionConstructor] public SimpleService(ILogger logger) { … } public SimpleService(String logFile) { … } } 1 2 container. RegisterType< IService, ServiceImpl>(new InjectionConstructor(typeof(ILogger) ) ) <type type="IService" mapTo="SimpleService"> <typeConfig> <constructor> <param name=" logger" parameterType="ILogger" /> </constructor> </typeConfig> </type> 3
Unity – wstrzykiwanie zależności przez właściwości public class SimpleService : IService { [Dependency] public ILogger Logger { get; set; } } 1 2 container. RegisterType< IService, ServiceImpl>(new InjectionProperty("Logger") ) <type type="IService" mapTo="SimpleService"> <typeConfig> <property name="Logger" propertyType="ILogger" /> </typeConfig> </type> 3
Unity – wstrzykiwanie zależności przez metody public class SimpleService : IService { [Dependency] public Init(Ilogger logger){ } } 1 2 container. RegisterType< IService, ServiceImpl>(new InjectionMethod("Init") ) <type type="IService" mapTo="SimpleService"> <typeConfig> <Method name="Init” /> </typeConfig> </type> 3
Unity – specjalizacja public class SimpleService : IService { [Dependency("UI")] public ILogger Logger { get; set; } } 1 2 container. RegisterType< Logger, ServiceImpl>("UI",new InjectionConstructortypeof(ILogger) ) <type name="UI" type="ILogger" mapTo="TraceSourceLogger"/> 3
Zasoby • CommonServiceLocator implementation:http://www.codeplex.com/CommonServiceLocator • Auto rejestracja dla unityhttp://autoregistration.codeplex.com/ • Automocking