Этот пост должен идти как предисловие к серии постов Реализуем EventPublisher. Но хорошая мысль, как это с ней часто бывает, пришла позже. :) Поэтому о назначении (читай решаемых проблемах) шаблона Event Aggerator расскажу только сейчас.
Для начала понадобиться пример проблемы. Пусть есть некое приложение c архитектурой MVVM. Скажем, модель для главного меню может выглядеть примерно так:
Решение: Необходим единый способ диспетчеризации событий главного меню, т.е. Event Aggregator. Напомню основные его интерфейсы:
1. Определить необходимые сообщения:
Для начала понадобиться пример проблемы. Пусть есть некое приложение c архитектурой MVVM. Скажем, модель для главного меню может выглядеть примерно так:
public class MainMenuVewModel
{
public MainMenuVewModel(
IClientsViewModel clientsViewModel,
ICountriesViewModel countriesViewModel,
ICitiesViewModel citiesViewModel,
IWindowManager windowManager)
{
_clientViewModel = clientsViewModel;
_countriesViewModel = countriesViewModel;
_citiesViewModel = citiesViewModel;
_windowManager = windowManager;
}
public void ShowClients()
{
_windowManager.Show(_clientsViewModel);
}
public void ShowCounrties()
{
_windowManager.Show(_clientsViewModel);
}
public void ShowCities()
{
_windowManager.Show(_clientsViewModel);
}
}
Проблема: Этот код не так уже плох, но это может быть далеко не полным перечнем всех зависимостей, которые понадобятся нашему меню. Это затрудняет его понимание, и не очень хорошо для тестирования. Ведь для модульного теста придётся написать как минимум 4 мок-объекта. Хотелось бы более элегантный способ, который бы не требовал каждый раз добавлять новую зависимость для нового пункта меню, что включает в себя как минимум три действия (объявление члена класса, объявление параметра конструктора, создание нового метода). Решение: Необходим единый способ диспетчеризации событий главного меню, т.е. Event Aggregator. Напомню основные его интерфейсы:
public interface IPublisher
{
void Publish<TMessage>(TMessage message);
}
public interface IListener<TMessage>
{
void ListenTo(TMessage message);
}
Что же с ними делать? Давайте по порядку: 1. Определить необходимые сообщения:
public class ShowClientsMessage {}
public class ShowCountriesMessage {}
public class ShowCitiesMessage {}
2. Переписать модель главного меню с помощью IPublisher.
public class MainMenuVewModel
{
public MainMenuVewModel(IPublisher publisher)
{
_publisher = publisher;
}
public void ShowClients()
{
_publisher.Publish(new ShowClientsMessage());
}
public void ShowCounrties()
{
_publisher.Publish(new ShowCountriesMessage());
}
public void ShowCities()
{
_publisher.Publish(new ShowCitiesMessage());
}
}
3. Написать обработчики событий:
public class ShowViewModelListener : TransientListenter<ShowClientsMessage>
{
public MainMenuVewModel(IWindowManager windowManager, IClientsViewModel clientsViewModel)
{
_windowManager = windowManager;
_clientsViewModel = clientsViewModel;
}
public void Handle(ShowClientsMessage message)
{
_windowManager.Show(_clientsViewModel);
}
}
// обработчики двух других событий выглядят идентично, для краткости их не привожу.
Что в итоге? Мы получили более простую модель главного меню за счёт вынесения сложности на другие классы. Сложность системы несколько увеличилась, но вместе с тем увеличилась и ее гибкость. Стоит ли игра свеч решать вам.
Комментариев нет:
Отправить комментарий