Основы di контейнеров
Post on 10-May-2015
1.009 Views
Preview:
DESCRIPTION
TRANSCRIPT
Предпосылки появления DI-контейнеров
Уральская группа пользователей .NET, март 2010
Павел Егоров, СКБ Контур pe@skbkontur.ru
http://xoposhiy.livejournal.com
S
O
L
I
D
RP — Single Responsibility Principle
CP — Open Closed Principle
SP — Liskov Substitution Principle
SP — Interface Segregation Principle
IP — Dependency Inversion Principle
— Хотим спроектировать хорошо!
— Быть готовым к грядущим изменениям!
SOLID
RP — Single Responsibility Principle
Модуль =
= одна обязанность =
= одна причина изменения
пихать все в один класс — НЕТ! :-\
плодить много мелких классов — ДА :-)
Iso8859Decoder
InvoiceConverter
Utf8Decoder
SRP всех вылечит! :-)
Iso8859Decoder
Invoice
Converter
Utf8Decoder
void Convert(){ var decoder = new Iso8859Decoder(); … decoder.Decode(…); …}
SOLIDIP — Dependency Inversion Principle
Классы должны зависеть от интерфейсов, а не от других классов.
InvoiceConverte
r
IDecoder
Iso8859Decoder Utf8Decoder…
public InvoiceConverter(IDecoder decoder)
{ this.decoder = decoder;}
…
public void Convert(){ … decoder.Decode(…); …}
SRP + DIP всех вылечат! :-)
new InvoiceConverter(new Iso8859Decoder());
или
new InvoiceConverter(new Utf8Decoder());
InvoiceConverte
r
IDecoder
Iso8859Decoder Utf8Decoder
реализация интерфейса использование
SRP
DIP
Miško Heverymisko.hevery.com
— Давайте жестко разделять:
код, содержащий логику программы
код, вызывающий конструкторы
new A(new B(…), new C(…))…new SmtpClient(smtpUrl);…new ConsoleLogger()…
IService
Locator
ServiceLocator
зависимости стали неявными…
хрупкость!
ServiceLocator
ServiceLocator
ServiceLocator
все зависят от ServiceLocator’а
жесткость!
Miško Heverymisko.hevery.com
Электронный бухгалтер
более 100 сервисов Rule of thumb:1 сервис на каждые 5-7 килобайт кодаДействительно МНОГО
серого тупого рутинного кода
время жизни
Автоматический поиск всех типов
с каждой новой «фичей» будет все хуже…Ленивая инициализация, коллекции, один объект на несколько интерфейсов, xml-конфигурирование, IDisposable, дочерние контейнеры, …
← ServiceLocator
ServiceLocator
Conventions over configuration(via RoboContainer)
Электронный бухгалтер
<castle> <components> <component id="JsonSerializer" service="SKBKontur.IB.Serialization.IDataSerializer, IB.Serialization" type="SKBKontur.IB.Serialization.JsonSerializer, IB.Serialization"> </component> <component id="BankReferenceSource" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceSource`1[[SKBKontur.IB.DataContracts.BankInfo, IB.DataContracts]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.Bank.BankReferenceSource, IB.ReferenceService, Version=1.0.0.0, Culture=neutral" > </component> <component id="BankReferenceImplementation" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceImplementation`2[[SKBKontur.IB.DataContracts.BankInfo, IB.DataContracts], [System.String]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.Bank.BankReferenceImplementation, IB.ReferenceService" > </component> <component id="BankReference" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReference`2[[SKBKontur.IB.DataContracts.BankInfo, IB.DataContracts], [System.String]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.Reference`2[[SKBKontur.IB.DataContracts.BankInfo, IB.DataContracts], [System.String]], IB.ReferenceService" > </component> <component id="BankReferenceWriter" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceServiceWriter, IB.ReferenceService" type="SKBKontur.IB.ReferenceService.Bank.BankReferenceServiceWriter, IB.ReferenceService" > <parameters> <dataSerializer>${JsonSerializer}</dataSerializer> </parameters> </component>
<component id="LocationReferenceSource" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceSource`1[[SKBKontur.IB.DataContracts.Address.LocationInfo, IB.DataContracts]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.KLADR.Location.LocationReferenceSource, IB.ReferenceService, Version=1.0.0.0, Culture=neutral" > </component> <component id="LocationReferenceImplementation" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceImplementation`2[[SKBKontur.IB.DataContracts.Address.LocationInfo, IB.DataContracts], [System.String]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.KLADR.Location.LocationReferenceImplementation, IB.ReferenceService" > </component> <component id="LocationReference" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReference`2[[SKBKontur.IB.DataContracts.Address.LocationInfo, IB.DataContracts], [System.String]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.Reference`2[[SKBKontur.IB.DataContracts.Address.LocationInfo, IB.DataContracts, Version=1.0.0.0, Culture=neutral], [System.String]], IB.ReferenceService" > </component> <component id="LocationReferenceWriter" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceServiceWriter, IB.ReferenceService" type="SKBKontur.IB.ReferenceService.KLADR.Location.LocationReferenceServiceWriter, IB.ReferenceService" > <parameters> <dataSerializer>${JsonSerializer}</dataSerializer> </parameters> </component>
<component id="StreetReferenceSource" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceSource`1[[SKBKontur.IB.ReferenceService.KLADR.Street.StreetInfo, IB.ReferenceService]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.KLADR.Street.StreetReferenceSource, IB.ReferenceService, Version=1.0.0.0, Culture=neutral" > </component> <component id="StreetReferenceImplementation" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceImplementation`2[[SKBKontur.IB.ReferenceService.KLADR.Street.StreetInfo, IB.ReferenceService], [SKBKontur.IB.ReferenceService.KLADR.Street.StreetReferenceSearchParams, IB.ReferenceService]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.KLADR.Street.StreetReferenceImplementation, IB.ReferenceService" > </component> <component id="StreetReference" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReference`2[[SKBKontur.IB.ReferenceService.KLADR.Street.StreetInfo, IB.ReferenceService], [SKBKontur.IB.ReferenceService.KLADR.Street.StreetReferenceSearchParams, IB.ReferenceService]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.Reference`2[[SKBKontur.IB.ReferenceService.KLADR.Street.StreetInfo, IB.ReferenceService], [SKBKontur.IB.ReferenceService.KLADR.Street.StreetReferenceSearchParams, IB.ReferenceService, Version=1.0.0.0, Culture=neutral]], IB.ReferenceService" > </component> <component id="StreetReferenceWriter" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceServiceWriter, IB.ReferenceService" type="SKBKontur.IB.ReferenceService.KLADR.Street.StreetReferenceServiceWriter, IB.ReferenceService" > <parameters> <dataSerializer>${JsonSerializer}</dataSerializer> </parameters> </component>
<component id="HouseReferenceSource" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceSource`1[[SKBKontur.IB.ReferenceService.KLADR.House.HouseInfo, IB.ReferenceService]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.KLADR.House.HouseReferenceSource, IB.ReferenceService, Version=1.0.0.0, Culture=neutral" > </component> <component id="HouseReferenceImplementation" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceImplementation`2[[SKBKontur.IB.ReferenceService.KLADR.House.HouseInfo, IB.ReferenceService], [SKBKontur.IB.ReferenceService.KLADR.House.HouseReferenceSearchParams, IB.ReferenceService]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.KLADR.House.HouseReferenceImplementation, IB.ReferenceService" > </component> <component id="HouseReference" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReference`2[[SKBKontur.IB.ReferenceService.KLADR.House.HouseInfo, IB.ReferenceService], [SKBKontur.IB.ReferenceService.KLADR.House.HouseReferenceSearchParams, IB.ReferenceService]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.Reference`2[[SKBKontur.IB.ReferenceService.KLADR.House.HouseInfo, IB.ReferenceService], [SKBKontur.IB.ReferenceService.KLADR.House.HouseReferenceSearchParams, IB.ReferenceService, Version=1.0.0.0, Culture=neutral]], IB.ReferenceService" > </component> <component id="HouseReferenceWriter" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceServiceWriter, IB.ReferenceService" type="SKBKontur.IB.ReferenceService.KLADR.House.HouseReferenceServiceWriter, IB.ReferenceService" > <parameters> <dataSerializer>${JsonSerializer}</dataSerializer> </parameters> </component>
<component id="IFNSReferenceSource" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceSource`1[[SKBKontur.IB.DataContracts.IFNSInfo, IB.DataContracts]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.IFNS.IFNSReferenceSource, IB.ReferenceService, Version=1.0.0.0, Culture=neutral" > </component> <component id="IFNSReferenceImplementation" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceImplementation`2[[SKBKontur.IB.DataContracts.IFNSInfo, IB.DataContracts], [SKBKontur.IB.ReferenceService.IFNS.IFNSReferenceSearchParams, IB.ReferenceService]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.IFNS.IFNSReferenceImplementation, IB.ReferenceService" > </component> <component id="IFNSReference" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReference`2[[SKBKontur.IB.DataContracts.IFNSInfo, IB.DataContracts], [SKBKontur.IB.ReferenceService.IFNS.IFNSReferenceSearchParams, IB.ReferenceService]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.Reference`2[[SKBKontur.IB.DataContracts.IFNSInfo, IB.DataContracts], [SKBKontur.IB.ReferenceService.IFNS.IFNSReferenceSearchParams, IB.ReferenceService]], IB.ReferenceService" > </component> <component id="IFNSReferenceWriter" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceServiceWriter, IB.ReferenceService" type="SKBKontur.IB.ReferenceService.IFNS.IFNSReferenceServiceWriter, IB.ReferenceService" > <parameters> <dataSerializer>${JsonSerializer}</dataSerializer> </parameters> </component>
<component id="RegionReferenceSource" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceSource`1[[SKBKontur.IB.ReferenceService.Region.RegionInfo, IB.ReferenceService]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.Region.RegionReferenceSource, IB.ReferenceService, Version=1.0.0.0, Culture=neutral" > </component> <component id="RegionReferenceImplementation" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceImplementation`2[[SKBKontur.IB.ReferenceService.Region.RegionInfo, IB.ReferenceService], [System.String]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.Region.RegionReferenceImplementation, IB.ReferenceService" > </component> <component id="RegionReference" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReference`2[[SKBKontur.IB.ReferenceService.Region.RegionInfo, IB.ReferenceService], [System.String]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.Reference`2[[SKBKontur.IB.ReferenceService.Region.RegionInfo, IB.ReferenceService], [System.String]], IB.ReferenceService" > </component>
<component id="VKTMOReferenceSource" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceSource`1[[SKBKontur.IB.ReferenceService.VKTMO.VKTMOInfo, IB.ReferenceService]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.VKTMO.VKTMOReferenceSource, IB.ReferenceService, Version=1.0.0.0, Culture=neutral"> </component> <component id="VKTMOReferenceImplementation" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceImplementation`2[[SKBKontur.IB.ReferenceService.VKTMO.VKTMOInfo, IB.ReferenceService], [System.String]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.VKTMO.VKTMOReferenceImplementation, IB.ReferenceService" > </component> <component id="VKTMOReference" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReference`2[[SKBKontur.IB.ReferenceService.VKTMO.VKTMOInfo, IB.ReferenceService], [System.String]], IB.ReferenceService" type="SKBKontur.IB.ReferenceService.Reference`2[[SKBKontur.IB.ReferenceService.VKTMO.VKTMOInfo, IB.ReferenceService], [System.String]], IB.ReferenceService" > </component> <component id="VKTMOReferenceWriter" lifestyle="singleton" service="SKBKontur.IB.ReferenceService.IReferenceServiceWriter, IB.ReferenceService" type="SKBKontur.IB.ReferenceService.VKTMO.VKTMOReferenceServiceWriter, IB.ReferenceService" > <parameters> <dataSerializer>${JsonSerializer}</dataSerializer> </parameters> </component> </components> </castle>
Windsor containerxml-конфигурирование
модуль AJAX подсказок
160 строк,11 Кб
3 строки конфигурирования2 из которых «не по делу» и сигнализируют о «мертвом», неиспользуемом коде.
DisclaimerИспользуя Windsor containerтоже можно практиковать подходConvention over Configuration! Наверное…
Подытожим• Наш проект ждут изменения.• SRP+DIP дают нам защиту от изменений, но…• …принуждают к тому, чтобы писать много мелких
классов.• Из мелких классов где-то нужно собирать граф
объектов.• Контейнеры всего лишь упрощают эту сборку.• А с convention over configuration упрощают
радикально!
Вопросы
Но будет много противных аргументов конструктора!
обычно бывает так:
а вовсе не так:
секретный слайд
— Аргументов будет мало,это я вам гарантирую! ;-)
Может быть конфигурировать в конструкторе?
секретный слайд
задавать через GUI
не загружать дважды
Conventions — это путь к хрупкости
Conventions Configuration
Неявность :-( :-)
Рутина :-))) :-(((
Ошибки
секретный слайд
Robert C. Martinobjectmentor.com
http://objectmentor.com/resources/articles/Principles_and_Patterns.pdfDesign Principles and Design Patterns
Дизайн плох, если…
…надо много переделывать
…трогать код опасно!
…проще сделать «в обход»
…использовать готовое решение не получается
жесткость
хрупкость
нетехнологичность
немобильность
[когда приходит новая задача]
rigidity viscosity
fragility immobility
top related