暴露类的内部组件,以防止编写过多代码并影响性能
Posted
技术标签:
【中文标题】暴露类的内部组件,以防止编写过多代码并影响性能【英文标题】:Exposing internal component of a class in order to prevent writing too much code and impact on performance 【发布时间】:2017-02-17 13:49:14 【问题描述】:假设我有一堂课
class B : public class QObject
Q_OBJECT
public:
B(QObject* parent=Q_NULLPTR);
signals:
void signalData(int data);
public slots:
void slotGetData();
private:
slotGetData()
是外部触发的,基本上从某处检索一些数据并使用signalData(int data)
将其发回。另一方面,我还有另一门课
class A : public class QObject
Q_OBJECT
public:
A(QObject* parent=Q_NULLPTR)
// Init B, move to thread, setup timer, connect timer's timeout to B's slotGetData()
// Connect B to A
connect(this->B, SIGNAL(signalData(int)), this, SLOT(slotGetData(int)));
signals:
// Emit signal containing data to another Qt component
void signalData(int x);
private slots:
// Connect B::signalData(int x) to this slot and re-emit the data using A::signalData(int x). Don't do anything with the data!
void slotGetData(int x);
private:
B* workerObj;
QThread worker;
QTimer workerTimer;
它主要负责实例化workerObj
,将其移动到worker
线程并将workerTimer
的timeout()
信号连接到B::slotGetData()
。
这个类的目的是使B
能够在想要使用它的第三方类中正确集成(多线程),例如:
class ThirdParty : public class QWidget
Q_OBJECT
public:
ThirdParty(QObject* parent=Q_NULLPTR)
// Init A
// Connect to B through A
connect(this->integrationObj, SIGNAL(signalData(int)), this, SLOT(slotGetData(int)));
private slots:
// Connect A::signalData(int x) to this slot and do something with the x (change UI, whatever)
void slotGetData(int x);
private:
A* integrationObj;
ThirdParty
类通过A
间接访问B
的特定功能。
现在我面临的困境如下:
我应该只是将来自B
的数据信号传递到A
并将其作为A
的信号公开还是
我是否应该只返回一个const
对B
的引用以允许其中包含A
的类(以便它可以使用B
)直接连接到B
的signalData(int x)
?
在第一种情况下(我有),我基本上必须镜像B
想要在A
内向外部提供的每个信号(通过在A
中提供相应的专用插槽以及基本上是与B
相同)。不用说,这会导致有太多相同的东西,并且也会有一些(即使只是轻微的)性能影响,因为我得到 2 个信号发射(从B
到 A
,然后从 A
到任何其他对象有A
) 和2 个槽调用(一个在A
中从B
获取信号,一个在任何其他具有A
的对象中从A
获取信号)。
第二种情况看起来不错,但我担心我会暴露B
的特性,包含A
的类可能不允许访问
如果实施第二种情况,我会有这样的事情(B
不会改变):
class A : public class QObject
Q_OBJECT
public:
A(QObject* parent=Q_NULLPTR);
const B* getB() const; // Return a reference to B that cannot be changed but can be used to expose B's slots and signals
signals:
private slots:
private:
B* workerObj;
QThread worker;
QTimer workerTimer;
class ThirdParty : public class QWidget
Q_OBJECT
public:
ThirdParty(QObject* parent=Q_NULLPTR)
// Init A
// Connect to B directly!
connect(this->A->getB(), SIGNAL(signalData(int)), this, SLOT(slotGetData(int)));
private slots:
// Connect B::signalData(int x) to this slot and do something with the x (change UI, whatever)
void slotGetData(int x);
private:
A* integrationObj;
我应该在这里做什么?遗憾的是没有私人信号,因此所有B
信号及其所有公共插槽都将被公开。如果要使用所有这些,那么这种暴露程度就没有问题,但除此之外……没有那么多。
【问题讨论】:
【参考方案1】:facepalm 我已经在我的另一个项目中找到了解决方案。 :D 我只需要在A
内部提供一个connectTo(QObject* thirdparty)
,它在内部将thirdparty
插槽仅连接到B
的特定信号,因此不会暴露B
中不应该暴露的东西!
另一个更好的解决方案是使用信号到信号连接 (connect(const QObject *sender, const char *signal, const char *method, Qt::ConnectionType type)
) 或使用子-父关系,尽管在后者中我必须确保实际上设置了父级。这也称为信号转发,需要 2 个信号但不需要额外的时隙。由于A
对ThirdParty
可见,我可以做(this
这里代表ThirdParty
)connect(this, SIGNAL(signalFromThirdPartyToB()), this->a, SIGNAL(signalFromAToB()))
将ThirdParty
信号的转发设置为B
到A
,然后执行实际信号-通过调用A
中的转发信号到B
中的插槽之间的插槽连接(this
这里代表A
)connect(this, SIGNAL(signalFromAToB()), this->b, SLOT(slotB()))
。
【讨论】:
信号槽系统是一种解耦类的方法。像你一样使用它来紧密耦合类似乎违反直觉。一般来说,如果 A 类和 B 类可以互操作但可以解耦,则将它们解耦并让其用户酌情组合/耦合它们。如果您碰巧重用它们,您当然可以使用辅助函数来分解 A 和 B 之间的常见耦合模式。理想情况下,A 不应该知道 B 的类型,反之亦然,它们应该可以单独构建。A
和 B
紧密耦合,除了一组非常有限的功能。 A
是使B
生存的一件事,基本上负责ThirdParty
实际获取任何数据。 B
提供的许多功能实际上不是插槽,而只是应该只有 A
才能访问的普通功能。以上是关于暴露类的内部组件,以防止编写过多代码并影响性能的主要内容,如果未能解决你的问题,请参考以下文章
React 限制渲染次数以防止无限循环...重新渲染次数过多
防止 Grails Controller 中的方法暴露为操作
收到此错误:错误:重新渲染过多。 React 限制渲染次数以防止无限循环