【问题标题】:Implement a "static observer pattern"实现“静态观察者模式”
【发布时间】:2013-04-04 09:50:33
【问题描述】:

我有一个带有方法模板的类:

struct Subject
{
  template <typename T>
  void doSomething()
  {
    ..
  }
};

现在每当doSomething 被调用(任何T)时,我都希望通知“观察者”:

  template <typename T>
  void onDoSomething()
  {
    ..
  }

观察者是一个方法模板很重要(包含方法的类模板也可以工作)。如果不是,我可以实现通用观察者模式。

可以修改Subject::doSomething()以便它调用一个方法。但是,Subject 类不应该“知道”具体的 Observer/observer 方法。

这背后的想法是:我在两个项目中使用Subject。我只需要(并且拥有)其中一个观察者。

有什么办法可以做到吗?

【问题讨论】:

  • 我忘了说我不能使用 C++11 的特性。但即使我可以,我也看不出这如何解决我的具体问题?
  • @Philipp 你是对的,它没有帮助。我误解了你的问题。

标签: c++ observer-pattern


【解决方案1】:

艰难的。它似乎归结为

通知必须在编译时可解析(它是一个模板)

同时,

通知在编译时不应该是可解析的(Subject 不应该知道观察者)

我可以想到两种方法:


1.添加doSomething的重载:

template <typename T, typename Observer>
void doSomething()
{
  doSomething<T>();
  Observer::onDoSomething<T>();
}

然后在项目A中调用单参数版本,在项目B中调用双参数版本。


2. 让定义 Subject 的文件包含一个标题,该标题将在每个项目中进行不同/不同的配置:

Subject.h

#include "observer_def.hpp"

struct Subject
{
  template <typename T>
  void doSomething()
  {
    ..
    notifyDoSomething<T>();
  }
};

项目 A 中的observer_def.hpp

template <typename>
inline void notifyDoSomething() {}

项目 B 中的observer_def.hpp

template <typename T>
inline void notifyDoSomething()
{
  MyObserver::onDoSomething<T>();
}

【讨论】:

  • 感谢您的想法。方法 1 不可取,因为 doSomething 在我不想更改的其他一些方法中被深度调用。方法 2 在我看来不像现代 C++ 风格。我想我找到的解决方案(请参阅其他答案)更符合我的需要,但无论如何 +1。
  • @Philipp:实际上,您的解决方案需要与Angew 使用的完全相同的预处理器机制......尽管我建议使用#ifdef ... #else ... #endif 块而不是两个不同的文件(它不那么令人困惑)。
  • @MatthieuM。这就是我说“不同/不同配置”的原因。我也试图覆盖#ifdef 选项。
【解决方案2】:

我终于通过模板特化的方式找到了一个令人满意的解决方案:

///signaling struct. Could be replaced with any other type.
struct SpecializedObserver{};

///unspecialized:
template <typename>
struct Observer
{
    template <typename T>
    static void onDoSomething()
    {
        //default: do nothing.
    }
};

///optional. Specialize in project A or leave aside in project B:
template<>
struct Observer<SpecializedObserver>
{
    template <typename T>
    static void onDoSomething()
    {
        std::cout << "doing something with " << typeid(T).name() << std::endl; 
    }
};

struct Subject
{
    template <typename T>
    void doSomething()
    {
      Observer<SpecializedObserver>::onDoSomething<T>();
      ..
    }
};

如果我不想要观察者,此解决方案不需要任何操作。如果我想要一个,我会专门使用 Observer 模板,如上所示。

编辑:这在我的测试中运行良好,但问题是如何在具有不同编译单元的场景中使用它 - 我应该在哪里定义专业化?

【讨论】:

  • 专业化应该在使用点可见。因此,它应该在定义Subject::doSomething 之前被包含...这需要预处理程序hackery (#ifdef...),因此有人想知道为什么要使用模板特化,而不仅仅是非模板Observer 类的不同定义。跨度>
猜你喜欢
  • 2011-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-12
  • 2013-10-28
  • 2012-05-11
  • 2015-01-30
  • 2017-01-23
相关资源
最近更新 更多