Я создал два абстрактных класса Subject и Observer, которые определяют классический интерфейс шаблонов Observer. Я извлекаю из них реализацию шаблона Observer. Наблюдатель может выглядеть так:
void MyClass::Update(Subject *subject)
{
if(subject == myService_)
{
DoSomething();
}
else if(subject == myOtherService_)
{
DoSomethingElse();
}
}
Это хорошо, и это говорит мне, кто что-то изменил. Однако, это не говорит мне, что изменилось. Иногда это нормально, потому что я просто собираюсь запросить у субъекта последние данные, но в других случаях мне нужно знать, что именно изменилось в предмете. Я заметил, что в Java есть метод notifyObservers () и метод notifyObservers (Object arg) для предположительного указания деталей об изменениях.
В моем случае мне нужно знать, произошло ли одно или несколько различных действий с субъектом, и, если это конкретное действие, узнать целое число, связанное с этим действием.
Итак, мои вопросы:
- Как в C ++ можно передать универсальный аргумент (как это делает Java)?
- Является ли Observer даже лучшим паттерном? Возможно, какая-то система событий?
ОБНОВИТЬ
Я нашел эту статью, в которой рассказывается о шаблоне шаблона Observer: реализация шаблона Subject / Observer с помощью шаблонов . Это заставило меня задуматься, не могли бы вы создать шаблон аргумента.
Я нашел этот вопрос переполнения стека, в котором говорится о шаблонировании аргумента: Шаблон Subject Observer на основе шаблона - должен ли я использовать static_cast или dynamic_cast . Однако у ОП, похоже, есть проблема, на которую никто не ответил.
Другая вещь, которую я мог бы сделать, это изменить метод Update, чтобы взять объект EventArg, как в:
void MyClass::Update(Subject *subject, EventArg arg)
{
...
А затем создайте подклассы EventArg для конкретных данных аргумента, а затем, я думаю, приведите их обратно к конкретному подклассу в методе обновления.
ОБНОВЛЕНИЕ 2
Также нашел статью, О создании асинхронных основ C ++ на основе сообщений; часть 2, в которой обсуждается, как субъект сообщает подробности о том, что изменилось.
Сейчас я серьезно думаю об использовании Boost.Signals . Использование моего собственного шаблона наблюдателя имело смысл, когда оно было простым, но шаблонирование типа и аргумента начинает усложняться. И мне может понадобиться безопасность потоков Boost.Signals2.
ОБНОВЛЕНИЕ 3
Я также нашел несколько интересных статей по шаблону наблюдателя:
Обобщающий наблюдатель Херб Саттер
Реализация шаблона наблюдателя в C ++ - Часть 1
Опыт реализации шаблона проектирования наблюдателя (часть 2)
Опыт реализации шаблона проектирования наблюдателя (часть 3)
Тем не менее, я переключил свою реализацию на использование Boost.Signals, который, возможно, немного раздулся для моих целей, успешно работает. И, вероятно, любые проблемы вздутия или скорости не имеют значения.
источник
Ответы:
Будь то C ++ или JAVA, уведомление для наблюдателя может прийти вместе с информацией о том, что изменилось. Те же методы notifyObservers (Object arg) также можно использовать и в C ++.
Как правило, проблема остается в том, что может быть несколько субъектов, отправляющих одному или нескольким наблюдателям, и, следовательно,
class arg
их нельзя жестко закодировать.Обычно лучший способ сделать это - создать аргумент arg в форме универсального сообщения / токена, который формирует один и тот же тип данных для разных классов, но значения различаются для разных наблюдаемых классов. В качестве альтернативы, если все такие значения уведомлений выводятся из класса в некотором базовом классе, который является общим для всех.
Для шаблона наблюдателя, то есть важно , чтобы Arg тип данных не жёстко между observee и наблюдателем - еще это сцепление , что делает вещи трудно развиваться.
РЕДАКТИРОВАТЬ
Если вы хотите, чтобы наблюдатель не только наблюдал, но и выполнял множество других задач в зависимости от того, что изменилось , вы также можете проверить шаблон посетителя . В шаблоне посетитель наблюдатель / посетитель вызывает модифицированный объект и, следовательно, может не только знать, что такое модификация, но и реально работать с ним.
источник
Object
(void *
,boost::any
или что - то так же родовое) , чем если бы вы передать конкретный тип, потому что с типом конкретного вы увидите во время компиляции , что - то изменилось, в то время как с общим типом его скомпилируется и перестанет работать, потому что наблюдатель не сможет работать с фактическими переданными данными.std::function
Boostboost::function
, Gtk +GClosure
, методы с привязкой к Python и т. Д.), Поэтому я просто определяю методы с соответствующими сигнатурами и прошу систему создать фактические наблюдатель. Связывание действительно является только одним способом, субъект определяет интерфейс для наблюдателей, но не имеет представления об их реализации.Существует несколько способов отправки универсального аргумента события «Мне нравится» в C ++.
1) Объявите аргумент события как void * и приведите его к нужному классу в обработчике события.
2) Объявите аргумент события как указатель / ссылку на новый класс / интерфейс, например (в ответ на ваш пример)
И иметь фактические классы аргумента события, производные от этого класса.
Что касается вашего вопроса относительно шаблона на основе проверки наблюдателя
http://www.codeproject.com/Articles/3267/Implementing-a-Subject-Observer-pattern-with-templ
источник
Я не знаю, является ли это каноническим именем, но из моих старых дней Smalltalk я помню термин «аспект», чтобы определить, что изменилось в наблюдаемом.
Это не так сложно, как ваша идея EventArg (и его подклассов); он просто передает строку (может быть даже целочисленной константой) от наблюдаемого к наблюдателю.
Плюс: есть только два простых метода (
update(observable)
иupdateAspect(observable, aspect)
Минус: наблюдателю, возможно, придется запросить наблюдаемую дополнительную информацию (например, ваше «целое число»)
источник