在信号槽机制和传统循环之间做决策

4

我想更新多个对象。我可以通过传统的循环来实现:


void ParentClass::updateItems(const float factor)
{
     for (Item *item : items()) {
        item->update(factor)
    }
}

...或者我可以使用信号槽(signal-slot)机制来实现:

class ParentClass : public QObject
{
    Q_OBJECT

Q_SIGNALS:
    // The signal which will be emitted by parent:
    void updateNeeded(const float factor);

private:
    void updateItems(const float factor);
}

// Signal is emitted here
void ParentClass::updateItems(const float factor)
{
     emit updateNeeded(factor);
}


class Item : public QObject
{
    Q_OBJECT

    Item(ParentClass *parent) : QObject()
    , m_parent(parent)
    {
        // Connect parent signal to each item slot at each item constructor
        QObject::connect(m_parent, &ParentClass::UpdateNeeded, 
                         this, &Item::handleUpdate);
    }

public Q_SLOTS:
    void handleUpdate(const float factor);

private:
    ParentClass *m_parent;
}


// The slot which handles emitted signal:
void Item::handleUpdate(const float factor)
{
    this->update(factor);
}

  1. 我已经测试了循环的方法,它可以工作。
  2. 我正在考虑使用信号槽机制,也许对于复杂的代码有一些好处。
  3. 我想知道哪种方法是应该这样做的,或者是否有更好的方法?

在写完我的问题后,我发现这篇文章非常有帮助,但我不确定它是否与我的问题直接相关。


2
我认为第一种方法更好:1)它更简单,2)避免了类之间的循环依赖。 - vahancho
1
没有人问有多少个items()update(factor)实际上是做什么的(例如,它是一个复杂的操作吗)? 这是否在GUI线程中运行? 没有更多细节,这看起来很像是一个观点问题。 - Maxim Paperno
@MaximPaperno 感谢您提到了使用信号槽方法的一个好处,即GUI响应能力 - user3405291
1
我认为这个问题中提供的两个答案在一般情况下都可能有用:https://dev59.com/nZjga4cB1Zd3GeqPGi5D - Maxim Paperno
1个回答

2

尽可能使用基于循环的方法,简单明了。

信号槽是一种非常松散耦合的接口方法 - 虽然有时候这很棒(主要是当其他选项不可行时..),但它比常规函数调用更加脆弱


1
我选择了循环的方法 =) - user3405291
2
哇...很好的观点。有什么支持这些关于松耦合和脆弱性的说法吗?在GUI线程中使用循环(如果我们看到的是这样)并不一定是一个好方法,无论它看起来多么简单。例如,它可能会阻塞UI,具体取决于update()方法实际执行的操作。有多少个items()?使用信号/槽,甚至是排队的信号/槽,可以大大提高应用程序的响应能力。在我看来。 :) - Maxim Paperno
1
@MaximPaperno 应用程序的响应速度是一个问题 - 但信号槽并不需要来解决这个问题。 - darune
排队连接即使所有内容都在同一线程中运行,也可以显著提高 GUI 的响应能力。否则,在循环内使用QCoreApplication::processEvents()会让人感到不适。仍然想知道“松耦合”和“脆弱”是什么意思。 - Maxim Paperno
1
@MaximPaperno 使用信号槽机制而不是直接调用是一种过度工程化的形式 - 除非有真正的理由使用。松散耦合(在某种程度上脆弱)来自于您可能会创造出来的混乱。N个对象“发出”信号给一些M个对象。如果您删除连接调用,则没有编译器错误等等可以帮助您。 - darune
“除非有真正的理由使用”,同意这个观点,我的观点基本上是从问题中看不出什么是“最佳”方法。当然,在给定的代码片段中,循环看起来更简单、更清晰。我也想知道“无论何时何地都要使用循环方法”的说法,这也取决于循环具体在做什么——正如其他地方提到的,关于循环有很多不同的意见。至于混乱……弄糊代码的方法有很多种。例如,如果一个“item”从未添加到“items()”中,编译器不会警告你。 - Maxim Paperno

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接