Denis Gladkikh
Russian   |  English

Основы создания модульных приложений

В дополнение к вебкасту Prism: Composite Application Guidance for WPF and Silverlight хотелось бы сделать еще несколько умозаключений. “Призма” на данный момент очень распространенный подход к разработке программных продуктов. За рубежом если вы найдете какую-нибудь работу на WPF или Silverlight первый вопрос, который вам зададут “А знаете ли вы призму?”. Чтобы узнать ее можете посмотреть первые 20 минут скринкаста, где я описываю основные моменты данного подхода. Узнать призму – это безусловно хорошо, но еще лучше знать зачем она нужна. Постараюсь привести пару простых примеров модульных приложений.

Модульные приложения

Главная идея Призмы – помощь в разработке модульных приложения. Под модулями понимается разделение именно по функциональности, а не на уровне архитектуры приложения. На самом деле, в хорошем приложении, каково бы оно не было, часто есть неявное разбиение на модули, вроде разброс на разные папки aspx страниц, либо xaml окон одной предметной области. Да и руководитель проекта раскидывает обычно задачи разработчикам в зависимости от функциональности. Например, если мы пишем CRM: то задачи можно разбить так – “ты занимайся информацией о клиентах, а ты занимайся расписанием (задачи, встречи и т.п.)”. Как раз это и можно разбить на настоящие модули, а именно на отдельные библиотеки. Когда разбивается на модули представление, то что-то нужно делать и со слоями, отвечающими за модель данных и доступа к данным (тут как связь между клиентом и сервером, если, к примеру, используем Silverlight, так и доступ к БД). Само собой, на каком то уровне дробление на модули прекратится либо из-за невозможности разбить, либо потому что нет необходимости. В любом случае, вряд ли вы будете дробить вашу базу данных на модули.

Что же даст нам четкое разбиение на модули? В случае Silverlight приложения – если наше приложение имеет разграничения прав доступа к функционалу, то в зависимости от прав пользователя подгружать разные модули: будет небольшой выигрыш в трафике. В этом же и в любом другом случае, если обеспечена достаточная независимость модулей друг от друга – возможность продавать разные компоновки нашего программного продукта. А как обеспечивать эту самую независимость? С этой задачей помогает иногда справиться Dependency Injection (DI). Почему иногда? Небольшие костыли все же нужно будет иногда подставлять.

Инъекция представлений

Давайте рассмотрим на примере как можно разобраться с зависимостями. Опять CRM. Пускай у нас есть модуль для работы с компаниями, и есть отдельный модуль с контактными лицами, который может быть в подставке с компаниями, а может и не быть. В случае, когда модуль “контактные лица” куплен – существует отдельный справочник с подробной информацией о каждом контактном лице, с историей взаимодействия с этим контактным лицом, в общем, не суть, просто много дополнительного функционала завязанного на контактном лице. Как же нам сделать эти модули действительно независимыми друг от друга? Ведь тут прослеживается тесная связь между компаниями и контактными лицами, а именно у компании есть список контактных лиц. Давайте зарисуем наше представление, есть форма детальной информации о компании и есть список контактных лиц этой компании, располагающейся на этой же странице. В случае купленного модуля контактных персон в списке должно быть больше информации, так же каждая строка должна иметь возможность открыть (перейти) на страницу детальной информации о персоне, а если модуль не куплен, тогда должно быть более простое представление с редактированием прямо в гриде.

sample form

Напрашивается такой выход, у нас есть Region “Contact Persons List” и нам необходима инъекция в этот регион определенной формы в зависимости от условия. Решаем задачу так: в модуле компаний создаем интерфейс IContactPersonsView – представление списка контактов, у которого есть, предположим, метод инициализации с передачей идентификатора компании. Помимо модуля контактных персон у нас будет еще модуль заглушка, который можем назвать BaseContactPersonsModule, предоставляющий нам только базовую функциональность работы с контактными лицами (только список). В обоих этих модулях будет реализация интерфейса представления IContactPersonsView. Теперь нам остается найти механизм, который сможет подставить в регион “Contact Persons List” необходимое представление. Тут нам поможет DI контейнер. Модули контактных персон при загрузке будут регистрировать соответствия своего типа к интерфейсу IContactPersonsView. А модуль компаний при отображении этого окна будет находить зарегистрированный тип к интерфейсу IContactPersonsView, создавать новый объект этого типа и делать инъекцию в необходимый регион. Еще нужно сделать зависимость, чтобы модуль компании загружался именно после модуля персон, чтобы он уже мог получить соответствие, какое представление зарегистрировано на его регион.

Работа с событиями

Есть другой пример, теперь у нас представление выглядит так:

sample form

Есть два контрола, один список компаний Companies List и второй зависимый от первого Details List, который опять же может отображать либо список контактных персон, либо список истории взаимодействия выбранной в верхнем контроле компании. В случае если это не модульное приложение, либо эти два контрола находятся на одной форме всегда – мы можем их связать при помощи самой формы – установить соответствие между выбранным элементом и списком детальной информации. В случае модульного приложения у нас нет понимания, на какой форме какое наше представление (контрол) будет располагаться, а так же нет должного представления, какой именно контрол будет там располагаться. Здесь нам бы помог некий механизм публикации событий. То есть контрол Companies List при выборе определенной компании публикует через данный механизм информацию об этом событии (каким-то образом его идентифицируя), а контрол Details List (либо даже это может быть набор контролов) просто подписывается через данный механизм на события этого типа. Самый простой способ реализация данного подхода – сделать статический event в каком-нибудь классе, к которому есть доступ как из Companies List, так и из Details List. В CompositeWPF для этого предоставлен Event Aggregator.

Итог

Как вы увидели из мною приведенных примеров CompositeWPF решает не так много задач, точнее он только помогает с одной задачей – модульностью. Притом модульность можно достаточно просто решить и без CompositeWPF. Создавать модульные приложения – очевидно, что хорошо и полезно. Чем меньше зависимостей между компонентами, тем проще будет создавать новый функционал. В начале затраты скорее всего по времени будут больше чем реализация в лоб, но в будущем выигрыш будет при должном подходе. И как видно из этих же примеров – остаются другие вопросы – что делать с доступом к данным, с объектами бизнес логики, стоит ли их разбивать на модули? Тут однозначного ответа нет, все зависит от задачи и Призма не дает ответы на данные вопросы.

Progg it


Вас также может заинтересовать

rss twitter

Комментарии (9)

Nimnul ( ) #
avatar
Итог:

Жутко тормознутое приложение
Denis Gladkikh ( ) #
avatar
Nimnul, почему же?

View injection делается при загрузке, да и притом там же все тоже самое как и при создании обычного приложения - создается View производиться injection.

EventAggregator - ну тут, практически, тоже стандартный механизм event'ов.
Сергей ( ) #
avatar
Здравствуйте, Денис, у меня такой вопрос, я читал про проект Acropolis, для создания smart client приложений с использованием WPF, и как я узнал этот проект заморозили почему-то, поэтому хотел спросить Prism похож на Acropolis или же это совсем разные вещи, то есть можно ли с помощью Prism создавать такие же приложения как предпологалось и с использованием Acropolis?
Denis Gladkikh ( ) #
avatar
Сергей, приветствую.

Мне сложно сравнить Prism с Acropolis. Насколько я знаю Acropolis - это был (или есть) определенный набор команд, каких-то тулзов для построения модульных приложений, все там делается через какие-то дизайнеры. В общем Acropolis - это фреймворк для построения приложений. Prism - это всего лишь подход к разработке приложений на WPF (небольшой фреймворк конечно же есть, но в сравнении с Acropolis его нет).

Я не игрался с Acropolis, только поверхностные взгляды, если можете скажите какие прелести у него были (или что вам нравилось), и мы попробуем с вами разъяснить заменит ли Prism Acropolis или нет.
Сергей ( ) #
avatar
Здравствуйте, Денис, возвращаюсь к своему вопросу по поводу создания smart client.
Вот тут http://www.gotdotnet.ru/blogs/zdebskis/6114/ я прочитал статью об Acropolis. Вообщем меня именно интересует создание приложений, где код бизнес- логики и UI разделены, то есть реализуется паттерн MVC или подобные ему. Из статьи по ссылке выше я понял, что Acropolis позволяет это удобно реализовать, причем использую WPF, а потом я прочитал, что этот проект заморозили, и хотелось бы узнать нет ли замены или же другого фреймворка, для удобной реализации подобных приложений? И можно ли с помощью Prism реализовать то же самое?
Заранее благодарю.
Denis Gladkikh ( ) #
avatar
Сергей, сам WPF(Silverlight) с легкостью дает нам возможность пользоваться MVC-подобными паттернами при разработке, а именно MVP или MVVM (недавно писал по ним небольшой обзор тут http://outcoldman.ru/ru/blog/show/184).
Prism же очень хорошо встраивается с этими архитектурами за счет того что можно применять IoC (и Prism призывает это делать) и за счет того что есть возможность создания View-First или Presenter-First.

По этому я с уверенностью могу сказать, что в этом плане Prism - заменяет Acropolis. Хотя может он и не дает это понятие в прямом виде, а все зависит еще и от разработчиков (про то же самое был и первый комментарий в приведенной вами ссылке)
Сергей ( ) #
avatar
Спасибо большое, Денис за разъяснения продолжу свое изучения Prism.
Антон ( ) #
avatar
Тоже разбираюсь с CAL. Затрудняет изучение, что у каждого автора своя реализация. Нет хорошего примера относительно простого приложения. Каждый пишет кто во что горазд.
http://msdn.microsoft.com/ru-ru/magazine/dd419663.aspx
http://channel9.msdn.com/posts/mtaulty/Prism--Silverlight-Part-10-A-Larger-Example-Email-Client/
http://www.slickthought.net/category/WPF-Composite-App.aspx
Denis Gladkikh ( ) #
avatar
Антон, конечно. Ну в принципе тому виной еще и то, что задачи у всех разные. Можно начинать всегда с одной идеологии, но когда проект начинает разрастаться, то просто идеологии уже не достаточно, и приходится пересматривать, передумывать и т.п. В реальных проектах, ИМХО, применить на 100% идеологию сложно без своих допилок, все на своих ошибках.
Добавить комментарий

Если вы хотите получать уведомления о новых комментариях к данному топику, укажите, пожалуйста, email и отметьте соответствующий пункт в форме. Если вы хотите добавить код в тексте комментария, то заключите его внутри тега [code]...[/code], более того можно уточнить язык, на котором написан данный код при помощи [code cs]...[/code], где вместо cs могут быть cs, html, xml, java, js, php, sql, cpp, css.

 

busy