观察者模式专业化

Observer pattern specialisation

本文关键字:专业化 观察者模式      更新时间:2023-10-16

我正在尝试将观察者模式用于一些输入内容,如下所示:

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