需要有关在类之间共享变量的 OOP 设计的帮助,这些变量单独使用计时器运行

Need help about OOP-design for sharing variables between classes, which run with a timer indipendently

本文关键字:帮助 变量 运行 计时器 单独使 OOP 共享变量 之间      更新时间:2023-10-16

假设我有 2 个类 FlyBee,它们的方法(分别运行和循环)在不同的时间运行

/* Fly */
using namespace boost::asio 
using namespace boost::posix_time
class Fly { 
... 
deadline_timer timeout_fly_;
char text_fly_;
Fly::Fly( io_service &io): timeout_fly_(io, seconds(4) ) 
{ 
    timeout_fly_.async_wait( boost::bind( &Fly::run, this ) );   
}
Fly::run(void) 
{ 
    std::cout << "Running Fly forever" << std::endl;
     timeout_fly_.expires_at( timeout_fly_.expires_at() + seconds(4)));  
     timeout_fly_.async_wait( boost::bind( &Fly::run, this ) ); 
}

和:

/* Bee */
class Bee { 
... 
deadline_timer timeout_bar_; 
char text_bee_;
Bee::Bee(io_service &io): timeout_bee_(io, seconds(2) ) 
{ 
    timeout_bee_.async_wait( boost::bind( &Bee::loop, this ) );  
}
Bee::loop(void) 
{ 
     std::cout << "Running Bee forever" << std::endl;
     timeout_bee_.expires_at( timeout_bee_.expires_at() + seconds(2) );
     timeout_bee_.async_wait( boost::bind( &Bee::loop, this ) ); 
 }

主要以以下方式开始:

/* main.cpp */
io_service io_service;
while(1) {
    io_service.run();
}

现在我遇到了一个问题,我需要在两个类之间交换一些数据(例如 char 文本)。但是我坚持了下来,无法解决这个问题,因为我不知道该怎么做。

我正在考虑将一个类传递给另一个类作为参考

using namespace boost::asio
using namespace boost::posix_time
class Fly {
...
  deadline_timer timeout_fly_;
  Bee bee_;
  char text_fly_;
...
  Fly::Fly(io_service &io, Bee &bee): timeout_fly_(io,seconds(4)), bee_(bee)
  {
    timeout_fly_.async_wait(boost::bind( &Fly::run, this));  
  }
  Fly::run(void)
  {
    std::cout << "Running Fly forever" << std::endl;
    text_fly_ = bee_->getTextInBee();
    timeout_fly_.expires_at(timeout_fly_.expires_at() + seconds(4));
    timeout_fly_.async_wait(boost::bind( &Fly::run, this));
  }

但我不确定这是否是一个很好的OOP设计。此外,这将使我的程序复杂化。我想让它尽可能简单。另一种选择是创建 2 个不同的线程,让它们运行并使用互斥锁保存结果以同步两个线程。

如何在两个类之间交换一般数据?

您可以将这两个类之间共享的任何内容包装在一个单独的对象中,并让这两个类访问该对象的指针。如果 Fly 和 Bee 同时使用数据存在争用条件,则可以使用互斥锁。

在处理OOP设计的问题之前,稍微更正一下:

在构造函数中,通过引用原始对象传递bee。 这将允许共享。 但是,您的bee_成员是纯值。 因此,构造函数将复制原始对象。 因此,您不会处理共享值,而是处理其克隆,保持原始值不变。

使其成为引用或指针。

设计问题

你的设计需要改进:蜜蜂和苍蝇是两个独立的对象,独立存在。 通过在构造时提供指向另一个对象的指针,可以在两者之间创建与现实不符的依赖关系。 也就是说,没有蜜蜂,你就不能再创造一只苍蝇了。 如果您希望bee对象访问fly对象,您将如何做?!

另类

您可以使用这种倒数指针,但不应在构造时填充它。您应该更喜欢单独的二传手。由于两个对象的设置应该匹配,因此您需要在两个 setter 中实现倒数对象中的设置,以避免无休止的递归。 一个更干净的分配器可以使用一个朋友函数来设置一个相互链接。

class Fly { 
    Bee *bee_;
    ...
    friend void peer(Bee&b, Fly&f);  
}; 
class Bee { 
    Fly *fly_;
    ...
public: 
    ...
    friend void peer(Bee&b, Fly&f);  
}; 
void peer(Bee&b, Fly&f) { 
    b.fly_ = &f; 
    f.bee_ = &b; 
    // this is simplified:  in realit you'd check if each object if already 
    // bound, and if yes, it would first reset the binding of the old corresponding pointer.  
}  

这两种情况下,您都可以通过从对等对象调用函数在对象之间传递数据,就像您所做的那样。完成getTextInBee()

另一种方法是使用第三个对象来表示消息/事件队列:

  • 然后,beefly可以使用此队列的观察者设计模式注册为观察者。
  • 任何蜜蜂或苍蝇都可以向此队列发布消息
  • 然后,队列将通知对象新消息。

这种设计比前一个设计稍微复杂一些,但它可以处理任意数量的对象(例如2只蜜蜂和5只苍蝇)。

这种实现可以通过使FlyBee都继承自相同的基类FlyingInsect来进一步改进。

最后,我根据以下模式重写了代码。它由一个包装类组成,该包装类至少创建三个对象:

  • 一类蜜蜂类型;
  • 一类飞行类型;
  • 一个类用于在两者之间交换数据;

在包装类中,我有如下所示的内容:

/* Wrapper class */
class Insect {
    /* Class with methods and members for sharing data */
    Data *exchange_data = new Data;
    /* Generate Bee */
    Bee bee;
    /* Generate Fly */
    Fly fly;

    public:
      Insect( boost::asio::io_service &io )
             : bee(io, exchange_data), fly(io, exchange_data);
}

请注意,当调用公共shared_data类的构造函数时,该类现在在初始化列表中传递。该类是包装类的成员,一旦创建,必须传递给现在有点不同的两个类:

/* Fly */
using namespace boost::asio 
using namespace boost::posix_time
class Fly { 
... 
deadline_timer timeout_fly_;
char text_fly_;
Data *shared_data;
Fly::Fly( io_service &io, Data *data): timeout_fly_(io, seconds(4)), shared_data(data)
{ 
    timeout_fly_.async_wait( boost::bind( &Fly::run, this ) );   
}
Fly::run(void) 
{ 
    std::cout << "Running Fly forever" << std::endl;
    shared_data->setMember( "I write something here" );
    timeout_fly_.expires_at( timeout_fly_.expires_at() + seconds(4)));  
    timeout_fly_.async_wait( boost::bind( &Fly::run, this ) ); 
}

/* Bee */
class Bee { 
... 
deadline_timer timeout_bar_; 
char text_bee_;
Data *shared_data;
Bee::Bee(io_service &io, Data *data): timeout_bee_(io, seconds(2)), shared_data(data)
{ 
    timeout_bee_.async_wait( boost::bind( &Bee::loop, this ) );  
}
Bee::loop(void) 
{ 
     std::cout << "Running Bee forever" << std::endl;
     shared_data->setMember( "I write something else here" );
     timeout_bee_.expires_at( timeout_bee_.expires_at() + seconds(2) );
     timeout_bee_.async_wait( boost::bind( &Bee::loop, this ) ); 
 }

在这些类(BeeFly)中,您可以使用指针指向 Data 类型的同一对象。在这两种情况下,您都可以调用方法并设置或获取类 Data 的成员。由于这两个类都在线程内封装,因此您需要在 Data 中使用互斥锁,以避免两个线程同时写入相同的资源或变量。

我不会假装拥有可以开发的最好的设计。但它有效,尽管使用了指针和其他东西,但它仍然有效,并且非常容易理解并遵循这种设计背后的基本思想。

我希望它可以帮助其他有同样麻烦的人。