观察者模式专业化

时间:2017-03-27 05:27:12

标签: c++ observer-pattern

我正在尝试将Observer模式用于某些输入内容:

class Observer
{
public:
    virtual void notify(Subject & o)=0;
};

class Subject
{
public:
    virtual void register(Observer * o)=0;
}

我有两个具体的主题(鼠标,键盘),具有类特定的功能,我希望具体的观察者调用(getkeypress,getmousemotion等)。

有没有办法在不更改接口或向下转换引用的情况下专门化具体观察者类中的notify函数?我已经尝试重载该函数,但显然这不起作用,因为具体的Subjects不知道派生的Observers。

2 个答案:

答案 0 :(得分:1)

您通常不会为观察者提供纯虚拟通知功能。相反,您的主题应该重新实现Observer :: notify对其所有主题的调用的“已更改”功能。这样,您可以在鼠标和键盘中重新实现以调用所需的功能。

这确实需要更改您的界面,因为现在它不太正确。

答案 1 :(得分:0)

  

有没有办法在不更改接口或向下转换引用的情况下专门化具体观察者类中的notify函数?

我认为没有。

但是,您可以通过使用作为dynamic_cast的子类的类模板来最小化使用Observer的位置数,并使用于实例化类模板的类型能够完全清楚衍生类型。

我已多次使用该模式。

解决方案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();
}

输出

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::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();
}

输出

In MouseObserver::notify
In KeyboardObserver::notify
In CombinedObserver::notify
In CombinedObserver::notify