我有两个班级
class Car
{
// class Car related methods
public:
setDriversName(QString);
private:
String driversName_; // This information comes from class DriversName
//Must get the drivers name info, when a particular event in this object occurs;
}
class DriversName
{
//class DriversName related methods
String getDriversName();
private:
String driversName_;
}
所以,现在我想在这两个类之间进行通信,更具体地说,我希望类Car
在Car Object中发生特定事件时从DriversName
类获取驱动程序的名称/强>
到目前为止,我有这两种方式,
C++ Message passing:
class Car
{
// class Car related methods
public:
setDriversNameObject(DriversName& );
setDriversName()
{
driversName_ = DriversName.getDriversName();
}
private:
DriversName driversName_; // So after setting the Driverclass object, i can directly
//access the driver's name, whenever the event occurs
String driversName_;
}
class DriversName
{
//class DriversName related methods
String getDriversName();
private:
DriversName driversName_;
}
OR
Qt
In mainWindow class:
connect(carObject,eventHasOccured(),this,updateDriversName());
void MainWindow::updateDriversName()
{
carObject->setDriversName(driversNameObject.getDriversName);
}
Class Car
{
Q_OBJECT
signals:
emit eventHasOccured();
public:
setDriversNameObject(DriversName& );
private:
DriversName driversName_;
}
Class DriversName
{
Q_OBJECT
String getDriversName();
private:
DriversName driversName_;
}
两种解决方案都一定能奏效。 以下是我的问题:
1)对于OO,上述方法是否存在任何缺陷 原则。
2)这种情况可能是最标准的方式 处理 ?
3)有没有其他更好的方法来处理给定的 情况。
感谢。
答案 0 :(得分:1)
1)就OO原则而言,上述方法是否存在任何缺陷。
第一种方法将Car
方法与DriversName
类紧密结合。
第二个将您的申请与Qt结合。如果你在整个应用程序中使用它,那不是什么大问题,但应该考虑它。此外,它将业务逻辑代码移动到主窗口类中,这可能不是一个好主意。
2)这种情况可以处理的最标准方法是什么?
这样做没有“一种明确的方式”。只是越来越好。
3)还有其他更好的方法来处理给定的情况。
对于“纯C ++”方法,您可以引入一个抽象接口来监听驱动程序名称更改(或者甚至更一般地用于监听通用名称更改)。 我在这里指的是基本上实现Observer模式。简化的实现可以是例如看起来像这样:
class NameChangeListener
{
public:
virtual void onNameChange(std::string const & newName) =0;
};
// This assumes change is initiated in DriversName class - not sure if this is correct
// Your code doesn't show the actual triggering of the change
class DriversName
{
public:
// ... other stuff
setNameChangeListener(NameChangeListener* ncl)
{
changeListener = ncl;
}
void setName(std::string const & newName)
{
// ... other stuff
if (changeListener)
changeListener->onNameChange(newName);
}
private:
// ..
NameChangeListener* changeListener;
};
class Car: public NameChangeListener
{
public:
// ... other stuff
void onNameChange(std::string const & newName) {
driversName = newName;
}
};
// somewhere outside:
Car c1;
DriversName n;
n.setNameChangeListener(c1);
对于Qt方法,可能最好引入一个封装这种关系的附加“Controller”类,而不是直接在主窗口中进行。
答案 1 :(得分:1)
在nyarlathotep的答案之上还有一些细节:
1)如果您确实需要在特定事件发生时进行更新,那么第一个解决方案是不够的,因为它不处理事件;一个人应该明确地呼叫Car
的{{1}}。你需要一般的信号/插槽或回调机制,就像第二种解决方案一样。在这种情况下,我认为你宁愿需要像
setDriversName()
应用程序/主窗口和connect(driversNameObject,nameChanged(string),carObject,setDriversName(string));
都不需要了解carObject
的任何内容。除此之外,我认为您的第二个解决方案中存在一些小错误(例如,driversNameObject
中没有setDriversName
方法。
2)和3)如果我还没有在QT项目中工作,我个人会避免使用QT的信号/插槽机制。这种机制完全绕过C ++语言,需要通过自己的工具进行源文件预处理。一个结果是在编译器有任何检查机会之前,所有内容(如方法名称)都被处理为字符串。另一个原因是你需要一种特定的方法来构建你的项目,这种方式比必要的更复杂,并且会使其他库的使用更加困难。
至于更多“纯C ++”解决方案,我打赌,例如Boost.Signals可以胜任这项工作,但它可能会带来太多你不需要的复杂性。
我开发了一个纯C ++抽象接口,它完全模仿基于delegates的QT信号/插槽的行为,但这涉及内部的低级内容,如转换为Car
。另一种选择当然是在内部使用void*
。在处理所有函数调用语言特征时,它仍然不是完全通用的,例如派生类中的方法,重载,虚方法,默认参数等(但Boost.Signals都不是)。我打算在完成它之前使用可变参数模板在C ++ 11中重新实现它。
同样,我(仍)不知道完美或事实上的标准解决方案。