观察者模式专业化
Observer pattern specialisation
我正在尝试将观察者模式用于一些输入内容,如下所示:
class Observer
{
public:
virtual void notify(Subject & o)=0;
};
class Subject
{
public:
virtual void register(Observer * o)=0;
}
我有两个具体的主题(鼠标,键盘(,具有特定于类的函数,我希望具体的观察者调用(getkeypress,getmousemotion等(。
有没有办法在不更改接口或向下转换引用的情况下将通知函数专用于具体的观察器类中?我尝试重载该函数,但显然这不起作用,因为具体的主体不了解派生的观察者。
你通常不会给观察者一个纯粹的虚拟通知函数。相反,您的主体应该重新实现一个"更改"函数,观察者::通知调用其所有主体。这,您可以在鼠标和键盘中重新实现以调用所需的函数。
这确实需要更改您的界面,因为现在它不太正确。
有没有办法在不更改接口或向下转换引用的情况下将通知函数专用于具体的观察器类中?
我认为没有。
但是,通过使用作为 Observer
子类的类模板,并使用于实例化类模板的类型完全了解派生类型,可以最大程度地减少使用dynamic_cast
的位置数。
我已经多次有效地使用了这种模式。
解决方案 1
这使用了一种模式,其中观察者只能观察一种类型的对象。
#include <iostream>
class Subject;
class Observer
{
public:
virtual void notify(Subject & o)=0;
};
class Subject
{
public:
// Remove the Observer argument from the public interface.
// Make the derived class construct the right type of observer
// and use the registerObserverImpl function to do the work.
// With this, client code doesn't need to know the kind of Observer
// a sub-class of Subject uses.
virtual void registerObserver() = 0;
void notifyObserver()
{
observer->notify(*this);
}
protected:
// Helper function for derived classes.
void registerObserverImpl(Observer * o)
{
observer = o;
}
private:
// The observer.
Observer* observer;
};
// A class template that is responsible for performing dynamic_cast
// and passing a reference to the derived type to the concrete Observer.
template <typename RealObserver>
class TemplateObserver : public Observer
{
using ConcreteSubject = typename RealObserver::SubjectType;
virtual void notify(Subject& o)
{
// The only place you need to use dynamic_cast.
RealObserver().notify(dynamic_cast<ConcreteSubject&>(o));
}
};
class Mouse : public Subject
{
public:
virtual void registerObserver();
};
// The concrete Observer of Mouse. It doesn't need to be derived from
// Observer since TemplateObserver takes care of that.
class MouseObserver
{
public:
using SubjectType = Mouse;
void notify(Mouse& m)
{
std::cout << "In MouseObserver::notifyn";
// Use the Mouse anyway you want.
}
};
void Mouse::registerObserver()
{
registerObserverImpl(new TemplateObserver<MouseObserver>());
}
class Keyboard : public Subject
{
public:
virtual void registerObserver();
};
// The concrete Observer of Keyboard. It doesn't need to be derived from
// Observer since TemplateObserver takes care of that.
class KeyboardObserver
{
public:
using SubjectType = Keyboard;
void notify(Keyboard& k)
{
std::cout << "In KeyboardObserver::notifyn";
// Use the Keyboard anyway you want.
}
};
void Keyboard::registerObserver()
{
registerObserverImpl(new TemplateObserver<KeyboardObserver>());
}
int main()
{
// Client code does not need to know about MouseObserver or
// KeyboardObserver.
Mouse m;
m.registerObserver();
m.notifyObserver();
Keyboard k;
k.registerObserver();
k.notifyObserver();
}
输出
In MouseObserver::notify
In KeyboardObserver::notify
解决方案 2
这使用了一种模式,在该模式中,观察者可以观察任意数量的对象类型。
#include <iostream>
class Subject;
class Observer
{
public:
virtual void notify(Subject & o)=0;
};
class Subject
{
public:
// Make the class polymorphic
virtual ~Subject() {}
void registerObserver(Observer * o)
{
observer = o;
}
void notifyObserver()
{
observer->notify(*this);
}
private:
// The observer.
Observer* observer;
};
// A class template that is responsible for performing dynamic_cast
// and passing a reference to the derived type to the concrete Observer.
template <typename RealObserver, typename RealSubject>
class TemplateObserver : public Observer
{
virtual void notify(Subject& o)
{
// The only place you need to use dynamic_cast.
RealObserver().notify(dynamic_cast<RealSubject&>(o));
}
};
class Mouse : public Subject
{
};
// The concrete Observer of Mouse. It doesn't need to be derived from
// Observer since TemplateObserver takes care of that.
class MouseObserver
{
public:
using SubjectType = Mouse;
void notify(Mouse& m)
{
std::cout << "In MouseObserver::notifyn";
// Use the Mouse anyway you want.
}
};
class Keyboard : public Subject
{
};
// The concrete Observer of Keyboard. It doesn't need to be derived from
// Observer since TemplateObserver takes care of that.
class KeyboardObserver
{
public:
using SubjectType = Keyboard;
void notify(Keyboard& k)
{
std::cout << "In KeyboardObserver::notifyn";
// Use the Keyboard anyway you want.
}
};
class CombinedObserver
{
public:
void notify(Mouse& m)
{
std::cout << "In CombinedObserver::notifyn";
// Use the Mouse anyway you want.
}
void notify(Keyboard& k)
{
std::cout << "In CombinedObserver::notifyn";
// Use the Keyboard anyway you want.
}
};
int main()
{
// Client code does not need to know about MouseObserver or
// KeyboardObserver.
Mouse m;
m.registerObserver(new TemplateObserver<MouseObserver, Mouse>());
m.notifyObserver();
Keyboard k;
k.registerObserver(new TemplateObserver<KeyboardObserver, Keyboard>());
k.notifyObserver();
m.registerObserver(new TemplateObserver<CombinedObserver, Mouse>());
m.notifyObserver();
k.registerObserver(new TemplateObserver<CombinedObserver, Keyboard>());
k.notifyObserver();
}
输出
In MouseObserver::notify
In KeyboardObserver::notify
In CombinedObserver::notify
In CombinedObserver::notify
相关文章:
- 如何设计具有不同类型的通知和观察器的观察者模式?
- 反射 + 函数指针与观察者模式
- 观察者模式不起作用
- 观察者模式:为什么主题应该是抽象的?
- 观察者模式专业化
- 如何在不必绑定到特定类的情况下实现观察者模式
- C++,函数指针与观察者模式
- C++11观察者模式(信号、插槽、事件、更改广播器/侦听器,或任何您想称之为的东西)
- 实施观察者模式C
- C++自己的观察者模式
- 不同可观察量的观察者模式
- 通过Boost信号的观察者模式2
- 具有类型信息的观察者模式(C++)
- 代码设计:观察者模式
- 观察者模式和继承:未调用正确的函数
- C++和Qt:观察者模式错误
- 在C++中实现观察者模式
- 多少听众是太多的观察者模式
- 当观察者希望观察不同的项目时实现观察者模式
- 通用观察者模式