Смешивание перечислений с классами событий в агрегаторе событий

Недавно я попытался реализовать свой собственный простой агрегатор событий. Меня очень вдохновила статья о агрегаторе событий в MSDN. Есть одна вещь, которую я заметил в агрегаторе событий в MSDN: события на самом деле являются классами сами по себе. Это совсем не плохо. Однако мне просто неудобно всегда создавать новый пустой класс для каждого отдельного небольшого события.

Причина, по которой я нахожу это неудобным, заключается в необходимости создавать класс для каждого отдельного детализированного события. Событие щелчка мыши, например, будет иметь двойной щелчок, одиночный щелчок, левый щелчок, правый щелчок и т. д. И все они будут иметь собственный класс. Это становится грязным через некоторое время.

Итак, в моей собственной реализации я подумал, что смогу сделать это таким образом, чтобы ClickEvent был классом, но все детализированные события, связанные с событием Click, были бы «типами» ClickEvent. В данном случае "типы" enum. Использование будет выглядеть примерно так:

//Publisher
eventAggregator.GetEvent<ClickEvent>.Publish(ClickEventType.Double_Click, eventArgs);

//Subscriber
eventAggregator.GetEvent<ClickEvent>.Subscribe(ClickEventType.Double_Click, handlerMethod);

Однако я не уверен, что эта реализация побеждает всю цель строго типизированного события? Теперь кажется, что ClickEvent — это просто контейнер для различных типов перечислений событий.


person Carven    schedule 12.12.2012    source источник


Ответы (2)


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

Если ваша проблема в основном заключается в организации файлов/классов и поддержании порядка в коде, почему бы просто не создать события кликов как вложенные классы в основном классе кликов.

e.g.

public static class ClickEvents // Prevent instantiation
{
    public class SingleLeft { }
    public class SingleRight { }
    public class DoubleLeft { }
    public class DoubleRight { }
    // Are there any more click events possible?!
}

eventAggregator.GetEvent<ClickEvents.SingleLeft>.Publish();

Кроме того, именно уникальность типа определяет сигнатуру события, поэтому для удовлетворения этой конкретной реализации требуется несколько типов.

По крайней мере, приведенное выше сохраняет ваш код обработчика чистым

void HandleLeftClick()
{
}

vs

void HandleClick(ClickArgs e) 
{
    if(e.ClickType == ClickType.Left)
    {
    }
}

Редактировать:

Также помните, что вы можете подписать несколько событий на один и тот же обработчик, если хотите обрабатывать более одного типа щелчка:

eventAggregator.GetEvent<ClickEvents.SingleLeft>.Subscribe(HandlerMethod);
eventAggregator.GetEvent<ClickEvents.SingleRight>.Subscribe(HandlerMethod);

(это будет работать в той редкой ситуации, когда подписчику все равно, какая кнопка мыши была нажата)

person Charleh    schedule 12.12.2012

Я думаю, вы упустили одну возможность. Видите ли, вам не нужно создавать новый класс для каждого уведомления. Вместо этого вы можете повторно использовать классы, но нести внутри некоторое дополнительное состояние произвольной сложности.

public class MouseClickNotification {

    public bool IsDoubleClick;
    public MouseButton ClickedButton;

    // any additional stuff

Таким образом, именно вы точно определяете степень детализации вашей модели уведомлений.

person Wiktor Zychla    schedule 12.12.2012
comment
Это работает, если вы хотите, чтобы какой-то код в обработчике определял, какой тип щелчка был вызван. Это прекрасно работает, если вы готовы продолжать писать этот код в каждом обработчике - я полагаю, что для вас будет меньшее из двух зол. - person Charleh; 13.12.2012
comment
Это работает всегда. Я имею в виду не то, чтобы предложить какую-то конкретную модель, лежащую в основе событий мыши, а показать, что мышление типа «давайте у нас будет новый класс для всего» ни к чему не приведет. Обратите внимание на его идею иметь классы для одиночного щелчка, двойного щелчка, щелчка левой кнопкой мыши и щелчка правой кнопкой мыши. Как он должен моделировать левые двойные щелчки и правые двойные щелчки таким образом? - person Wiktor Zychla; 13.12.2012
comment
Просто создайте класс для каждого из этих конкретных событий, например. Одинарное левое, двойное левое. Я не говорю, что ваша реализация неверна, это может показаться естественным, но очевидно, что в каждом отдельном обработчике щелчка вы получаете небольшой дополнительный код, чтобы определить, какой это был тип щелчка, в то время как создание типа для каждое сообщение о событии дает вам возможность узнать, какой тип события был входящим, без дополнительной обработки в обработчике. Что бы ни облегчило вам жизнь, я просто предпочитаю реализацию типа для каждого сообщения. - person Charleh; 13.12.2012
comment
Я не ответил на последний бит - для события «Click» (когда пользователю все равно, какая кнопка была нажата) ... ну, я думаю, что такие ситуации довольно редки (нечасто, что не имеет значения, какая кнопка была нажата!) но если это так, то подписчик может подписаться как на события кликов SingleLeft, так и на SingleRight. Это приведет к запуску одного и того же обработчика независимо от того, что было нажато, поэтому у вас все равно будет более простая реализация. На мой взгляд, подписка должна решить, какие события должны запускать обработчик. Обработчики не обязаны фильтровать события. - person Charleh; 13.12.2012
comment
Библиотека базовых классов предлагает модели для обработки информации о щелчках мыши, например, класс MouseEventArgs из System.Windows.Forms. Единый тип уведомления, отфильтрованный на стороне клиента. Есть ли где-нибудь примеры моделей, похожих на вашу? - person Wiktor Zychla; 13.12.2012
comment
Вероятно (например, я не могу привести вам никаких примеров, кроме моего собственного кода), но только потому, что Microsoft делает это с EventArgs, не означает, что его нужно использовать для любого другого шаблона на основе подписки. Реализация, представленная в MSDN, предоставляет делегат фильтра, который позволяет вам фильтровать сообщения на основе содержимого сообщения до вызова обработчика, так что это лучшая альтернатива. Как я уже сказал, это просто тонкость - person Charleh; 13.12.2012