2/17/2007 5:27:00 AM

Сегодня немного расскажу об архитектуре Composite Application Blocks (Web и UI) и о том, как ее использовать "во благо". Речь в основном пойдет о двух фундаментальных вещах: сервисах и шаблоне проектирования M-V-P (Model-View-Presenter).

В процессе работы над (любым) программным продуктом всегда хочется сделать так, чтобы отдельные части этого продукта, работая вместе "как часы", при этом как можно меньше зависели друг от друга.  Для того, чтобы работа над одной из частей никак не затрагивала другие части или чтобы легко можно было вообще заменить одну из частей так, чтобы остальные части об этом ничего не узнали. Эта проблема называется "связанностью" и решение ее тем лучше, чем меньше различные части системы знают о том, как реализованы другие.

Слабой связанности в Composite Application Blocks можно добиваться посредством создания сервисов.
Кто такой сервис? Сервисом может быть любая независимая часть вашего приложения.
Сервис дает возможность приложению задавать вопросы типа "что" не заботясь об ответах на вопрос "как". Наше приложение просит сервис дать список пользователей - и получает его не заботясь о том, был ли список получен из БД или с Веб-сервиса. Приложение просит сервис информировать пользователя о прогрессе, не заботясь о том, будет ли пользователю показан ProgressBar или отобразится окошечко "Please Wait".
Приложение знает что надо делать. Сервис знает как надо делать. Приложение знает, что где-то есть, кто-то, кого можно пнуть, чтобы он сделал свою работу.

О том, как это реализуется.
Сервис обычно состоит из "двух частей" - интерфейса сервиса и его реализации. Интерфейс сервиса обычно размещается где-нибудь в доступном для всех (интересующихся) частей приложения месте (в Shared-библиотеке), а реализация - где придется там, где удобнее реализовывать этот интерфейс (например в каком-то модуле).

Например, мы определим интерфейсы ISourceControlService и IProgressService в общей библиотеке, чтобы все части приложения имели к ним доступ. После этого мы можем создать модуль SourceSaveVersionController, в котором создать класс SourceSaveService : ISourceControlService, которая будет работать работать с Microsoft SourceSave.
При загрузке и инициализации этого модуля происходит регистрация сервиса в системе:

Services.AddNew<SourceSaveService, ISourceControlService>();

С этого момента из любой части приложения мы можем обратиться к сервису, отвечающему за контроль версий, получить экземпляр, реализующий ISourceControlService и даже не задумываться о том, с какой именно системой контроля версий мы имеем дело:

ISourceControlService scControl = Services.Get<ISourceControlService>();

И теперь если мы заменим SourceSaveVersionController на, скажем, ClearCaseVersionController с соответствующей реализацией ISourceControlService, то для всего остального приложения эта смена пройдет более чем прозрачно. Потому, что остальное приложение знать не знает ни про какие модули и реализации, оно общается только с известным ему интерфейсом.

Для IProgressService можно поступить еще хитрее: реализовать этот интерфейс в главной форме приложения и зарегистрировать ее саму как сервис типа IProgressService. А можно сделать как-то иначе, придумать что-то другое, ведь уже стало понятно, что остальному коду совершенно безразлично то, кто предстанет перед ними под личиной IProgressService и как он будет выполнять свою работу :)

Сама работа с сервисами в Composite Application Blocks тоже очень удобна.
Например, для регистрации сервиса в CAB можно использовать такую конструкцию:

[Microsoft.Practices.CompositeUI.Service(typeof(IComponentsProvider))]
public class AccessComponentsProvider : IComponentsProvider
{.....}

В этом случае при загрузке модуля экземпляр сервиса будет автоматически создан и зарегистрирован.

Там, где нам необходимо общаться с сервисами, и в CAB и в Composite Web AB можно сделать так:

[ServiceDependency]
public IAuthorizationService AuthService
{
   
get { return _authService; }
   
set { _authService = value; }
}

ObjectBuilder сам найдет для вас подходящий сервис IAuthorizationService (если, конечно, он был зарегистрирован) и вызовет присвоит ссылку на него свойству AuthService. В случае, если нужный сервис зарегистрирован не был, вы получите null. Однако, в конструктор аттрибута ServiceDependency можно передать булевый параметр для того, чтобы ObjectBuilder возбуждал исключение если сервис найти не удается.

В заключение хотел бы еще раз подчеркнуть: всю функциональность, которую можно сделать сервисом, настоятельно рекомендую делать именно сервисом. Это позволяет добиться большой гибкости за счет отделения интерфейса от реализации и легко поддерживается. 
В этом случае не нужно думать о том, экземпляр какого класса создать или какой фабрикой классов воспользоваться для того, чтобы сделать что-то. Не нужно и создавать десятки экземпляров в различных местах для того, чтобы воспользоваться определенным функционалом - всегда есть т��т, кто готов выполнить ваш запрос.
Наконец, не нужно знать каким синглтоном воспользоваться, как и вообще плодить синглтонов, которые не дают такой гибкости при работе с ними.

Используйте сервисы - и да будет вам счастье :)

Tags:

Comments (2) -

2/26/2007 8:16:20 PM

cadet354

Я так понял, что ObjectBuilder это контейнер для реализации IoC.
А как эти service работают в многопоточной среде, как с lifetime этих сервисов?

Как это работает в реальных условиях, насколько большой overhead по сравнению со шпагетти кодом Smile

cadet354

2/27/2007 6:08:09 AM

Отлично это работает в реальных условиях ;) По крайней мере в CAB.
Что касается лайвтайма - то в CAB сервис "умирает" вместе с содержащим его воркайтемом. Ну, либо тогда, когда ты явно вызовешь метод Remove.

Что касается ObjectBuilder, то да, это реализация IoC, достаточно хорошая.

Про спагетти-код я говорить не буду. Ибо приходится с ним сталкиваться периодически и это вгоняет меня в транс. Если говорить об оверхеде, то то, во что превращается спагетти-код после некоторого времени его поддержки, оптимальностью, мягко говоря, не блещет.

Alexey Raga

Comments are closed

Powered by BlogEngine.NET 2.5.0.6

About the author

Alexey Raga Alexey Raga
.NET software developer.

E-mail me Send mail

Twitter

Widget Twitter not found.

Root element is missing.X


Recent posts

Archive

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2012

Sign in