高级观察者模式(相互)替代

时间:2014-09-16 08:41:54

标签: c++ observer-pattern

假设有一个类Data,它不仅包含可以修改的数据,还包含构建在包含的数据成员上的重要成员函数。

进一步假设有一个HandleData类,它获取一个指向Data实例的指针。 HandleData获取数据并计算一些重要的成员编号(已在初始化时)。初始化和数据更改期间的数字计算很重要,因为一次又一次地使用函数成员调用计算它们是昂贵的(例如执行集成)。 如果数据发生变化,HandleData将通过更新数字来适应变化。

到目前为止,问题只是观察者模式。现在,HandleData还提供另一个名为TreatHandleData的类,这样Data的更改意味着HandleData中的更改,这再次暗示了TreatHandleData的更改。在所有情况下,为了减少计算时间,每次Data / HandleData更改时都必须初始化一些数字。

如果所有这些类都需要可复制,那么混乱似乎是完整的。

我真的希望看到我在下面写的内容的一些替代方案。特别是因为在我的情况下,所有类必须从一个类派生。它似乎不对。

我的简单尝试是:

#include <algorithm> // remove
#include <memory>    // shared_ptr
#include <assert.h>
#include <iostream>  // cout, cerr, endl
#include <vector>

class MutualObserver
{
public:

  MutualObserver() {}

  // copy ctor resets the list of observers
  MutualObserver(const MutualObserver & src) : observer(0) {}

  virtual ~MutualObserver() {};

  // assign op. must be empty to not have a list of observers that persists
  MutualObserver& operator = ( const MutualObserver &rhs ) { return *this; }

  // adds observer
  void add ( MutualObserver * o )
  {
    bool good = true;
    for ( uint i = 0; i<observer.size(); i++)
      if ( observer[i] == o ) good = false;

      if ( good && (o != NULL) ) observer.push_back(o);
  }

  // removes observer
  void remove ( MutualObserver * o )
  {
    if ( o == NULL )
      std::cout<<" in Data::remove - observer is NULL "<<std::endl;

    bool good = true;
    for ( uint i = 0; i<observer.size(); i++)
      if ( observer[i] == o ) good = false;

    if (good && o!=NULL )
      observer.erase
        ( std::remove( observer.begin(), observer.end(), o),observer.end() );
  }

  /// updates obserer o
  void update_observer ( MutualObserver * o )
  {
    for ( uint i = 0; i<observer.size(); i++ )
      if  ( observer[i] == o ) observer[i]->update_yourself();
  }

  /// updates all observers
  void update_all_observers ()
  {
    for (uint i = 0; i<observer.size(); i++)
    {
      observer[i]->update_yourself();
    }
  }

  /// updates all important members esp. of derived classes
  /// observer method, should be implemented for all observers
  virtual void update_yourself () {}

protected:
  std::vector<MutualObserver*> observer;

};


class Data : public MutualObserver
{
public:
  Data () : A(42.) {}
  void setA ( double x ) { A = x; update_all_observers(); }
  double getA () { return A; }
  double multiply ( double x ) { return A * x; } 

private:
  double A;  
};


class HandleData : public MutualObserver
{
  double important_variable;
  std::shared_ptr<Data> mySource;

public:
  HandleData ( std::shared_ptr<Data> source ) 
    :  mySource(source), important_variable(0.)
  {
    assert( source != NULL );
    mySource->add(this); 
    update_yourself();
  }

  HandleData ( const HandleData &src ) 
    :  MutualObserver(src), mySource( src.mySource ),
       important_variable( src.important_variable )
  {
    assert( mySource != NULL );
    mySource->add(this); 
    update_yourself();
  }

  virtual ~HandleData() { if ( mySource!=NULL ) mySource->remove(this); }

  virtual void update_yourself ()
  {
    double A = mySource->getA();
    important_variable = A *2.*3.14;
  }

  double getVariable() const { return important_variable; }
};


class TreatHandleData : public MutualObserver
{
  double important_variable;
  std::shared_ptr<HandleData> mySource;

public:
  TreatHandleData ( std::shared_ptr<HandleData> source ) 
    :  mySource(source), important_variable(0.)
  {
    assert( source != NULL );
    mySource->add(this); 
    update_yourself();
  }

  TreatHandleData ( const TreatHandleData &src ) 
    :  MutualObserver(src), mySource( src.mySource ), 
       important_variable( src.important_variable )
  {
    assert( mySource != NULL );
    mySource->add(this); 
    update_yourself();
  }

  virtual ~TreatHandleData() { if ( mySource!=NULL ) mySource->remove(this); }

  virtual void update_yourself ()
  {
    double A = mySource->getVariable();
    important_variable = A * 365.;
  }

  double getVariable() const { return important_variable; }
};

int main()
{
  std::shared_ptr<Data> observable ( new Data() );
  std::shared_ptr<HandleData> observer ( new HandleData(observable) );
  std::shared_ptr<TreatHandleData> myTHD ( new TreatHandleData(observer) );

  // copy
  std::shared_ptr<Data> observable2 ( new Data( *observable ) );
  std::shared_ptr<HandleData> observer2 ( new HandleData(*observer) );
  std::shared_ptr<TreatHandleData> myTHD2 ( new TreatHandleData(*myTHD) );

  std::cout << "initial Data:            "<< observable->getA() << std::endl;
  std::cout << "initial HandleData:      "<< observer->getVariable() << std::endl;
  std::cout << "initial TreatHandleData: "<< myTHD->getVariable() << std::endl;

  std::cout << " COPY: " << std::endl;

  std::cout << "initial Data:            "<< observable2->getA() << std::endl;
  std::cout << "initial HandleData:      "<< observer2->getVariable() << std::endl;
  std::cout << "initial TreatHandleData: "<< myTHD2->getVariable() << std::endl;

  double a = 99.31232;
  std::cout << " Changing A to " << a << std::endl;
  observable->setA( a );  
  std::cout << " (diff) changed Data:            "<< observable->getA() << std::endl;
  std::cout << " (diff) changed HandleData:      "<< observer->getVariable() << std::endl;
  std::cout << " (diff) changed TreatHandleData: "<< myTHD->getVariable() << std::endl;

  std::cout << " COPY: " << std::endl;

  std::cout << " (same) changed Data:            "<< observable2->getA() << std::endl;
  std::cout << " (diff) changed HandleData:      "<< observer2->getVariable() << std::endl;
  std::cout << " (same) changed TreatHandleData: "<< myTHD2->getVariable() << std::endl;

  return 0;
}

结果是:

初始数据:42

初始HandleData:263.76

初始TreatHandleData:96272.4

COPY:

初始数据:42

初始HandleData:263.76

初始TreatHandleData:96272.4

将A更改为99.3123

(差异)改变数据:99.3123

(差异)改变了HandleData:623.681

(差异)更改了TreatHandleData:96272.4

COPY:

(同)更改数据:42

(差异)改变了HandleData:623.681

(同)更改了TreatHandleData:96272.4

应该如此。

1 个答案:

答案 0 :(得分:0)

根据我的理解,你不想在每次getter调用时重新计算HandleData和TreeHandleData上的数据,因为计算是扩展的。

为什么不使用延迟更新方法是getter检查底层数据是否已更改并仅在这种情况下重新计算。这样就根本不需要使用观察者模式。