Страницы

вторник, 6 сентября 2011 г.

Реализуем EventPublisher. Послесловие.

   Этот пост должен идти как предисловие к серии постов Реализуем EventPublisher. Но хорошая мысль, как это с ней часто бывает, пришла позже. :) Поэтому о назначении (читай решаемых проблемах) шаблона Event Aggerator расскажу только сейчас.
  Для начала понадобиться пример проблемы. Пусть есть некое приложение 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);
  }
}
// обработчики двух других событий выглядят идентично, для краткости их не привожу. 
  Что в итоге? Мы получили более простую модель главного меню за счёт вынесения сложности на другие классы. Сложность системы несколько увеличилась, но вместе с тем увеличилась и ее гибкость. Стоит ли игра свеч решать вам.

Комментариев нет:

Отправить комментарий