C++ 观察者模式专业化
我正在尝试使用观察者模式进行一些输入,例如:C++ 观察者模式专业化,c++,observer-pattern,C++,Observer Pattern,我正在尝试使用观察者模式进行一些输入,例如: class Observer { public: virtual void notify(Subject & o)=0; }; class Subject { public: virtual void register(Observer * o)=0; } 我有两个具体的主题鼠标、键盘,以及类特定的函数,我希望具体的观察者调用getkeypress、getmousemotion等 有没有办法在不改变接口或向下转换引用的情况
class Observer
{
public:
virtual void notify(Subject & o)=0;
};
class Subject
{
public:
virtual void register(Observer * o)=0;
}
我有两个具体的主题鼠标、键盘,以及类特定的函数,我希望具体的观察者调用getkeypress、getmousemotion等
有没有办法在不改变接口或向下转换引用的情况下,在具体的观察者类中专门化notify函数?我尝试过重载函数,但显然这不起作用,因为具体的主体不知道派生的观察者。通常不会给观察者一个纯虚拟的通知函数。相反,您的主题应该重新实现一个已更改的函数,Observer::notify调用其所有主题。这样,您可以在鼠标和键盘中重新实现以调用所需的函数 这确实需要对所展示的界面进行更改,因为现在它并不完全正确 有没有办法在不改变接口或向下转换引用的情况下,在具体的观察者类中专门化notify函数 我想没有 但是,通过使用作为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::notify\n";
// 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::notify\n";
// 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();
}
解决方案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::notify\n";
// 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::notify\n";
// Use the Keyboard anyway you want.
}
};
class CombinedObserver
{
public:
void notify(Mouse& m)
{
std::cout << "In CombinedObserver::notify\n";
// Use the Mouse anyway you want.
}
void notify(Keyboard& k)
{
std::cout << "In CombinedObserver::notify\n";
// 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();
}
你能详细说明一下吗?嗯,这是一种有趣的方法,但在这种情况下,具体的观察者需要与其他对象交互,一个摄影机类,我不确定这会有多有用。@IanYoung,我想这不会是一个问题,但在我看到相机的外观以及您希望如何使用它作为观察者之前,我无法提出任何具体的建议。@R Sahu这不是我的确切意思,但我可以看到混乱。我的意思是,澄清一下,我有一个moduleobserver,它充当控制器主体(在本例中为键盘或鼠标)和相机之间的中介。中介所做的只是查询鼠标移动和/或按键,然后调用相机上的移动/旋转函数。@IanYoung,听起来很合理。您可以创建两个观察者,而不是一个-一个用于键盘,一个用于鼠标。它们一起可以执行模块的角色。在我的建议中,使模块同时成为键盘和鼠标的观察者将是一个问题。@R Sahu到目前为止听起来不错,但我发现自己回到了最初的问题,即当观察者->通知*这一点时;通过键盘或鼠标调用。我仍然需要将每个主题向下转换到键盘或鼠标对象,以便查询它们,我正试图避免这种向下转换。