【发布时间】:2016-09-23 23:26:33
【问题描述】:
我正在就我目前的方法是否有意义寻求建议。如果没有,我想要一个关于某种类型的设计模式的建议,它可以用来代替我目前的直觉。
我的前提是我的相机需要带有 CameraLink 或 CoaXPress 电缆接口的图像采集卡才能连接到 PC。相机和计算机之间的所有通信和数据传输都必须使用图像采集卡来控制,因此这两个物理硬件对象之间的耦合非常紧密。
我的问题是我想创建一个“相机”对象(用于 GUI),它有一个“FrameGrabber”卡对象,用于获取数据和发送/接收命令和数据.但是,我有许多不同类型的图像采集卡。我们称它们为 CoaxGrabberA、CoaxGrabberB、LinkGrabberA 和 LinkGrabberB。 CoaxGrabbers 需要一组与 LinkGrabbers 不同的初始化、setter 和 getter 参数。
因此,我认为我需要使用两个级别的继承,但从我所阅读的所有内容来看,应该很少使用继承,并且应该优先使用组合。因此,我非常怀疑我的设计决策,并寻求某种更好的设计。这是一些半生不熟的代码的示例。这有点冗长,但重要的部分是 CoaxGrabberA、CoaxGrabberB、LinkGrabberA 和 LinkGrabberB 是 FrameGrabber 的孙子的概念,Camera 必须可以访问它们。其他的一切都是为你可能需要的细节填肉。
我的目标是在运行时选择我想要用于我的相机对象的任何帧抓取器(任何品牌/模型/接口)。此外,我想轻松访问该孙帧捕获器类型独有的所有成员函数,以在运行时修改硬件的行为。
我的问题是“有没有一种特定的设计模式可以解决我不知道的问题,这比使用我的天真、直观的方法更容易”
//-----------------------------------------
// Parent Class
//=========================================
class FrameGrabber {
public:
virtual void sendCommandString(std::string cmd) = 0;
virtual void startAcquisition() = 0;
virtual void stopAcquisition() = 0;
};
//-----------------------------------------
// Children Classes
//=========================================
class CoaxGrabber : FrameGrabber {
public:
//functions unique to coax grabbers
virtual void setCommAddress(int commAddress) = 0;
virtual void setStatusPort(int statusPort) = 0;
//functions universal to all grabbers
virtual void sendCommandString(std::string cmd) = 0;
virtual void startAcquisition() = 0;
virtual void stopAcquisition() = 0;
protected:
int _commAddress;
int _statusPort;
};
class LinkGrabber : FrameGrabber {
public:
//functions unique to link grabbers
virtual void setBaudRate(int baudRate) = 0;
virtual void setNumChannels(int numChannels) = 0;
//functions universal to all grabbers
virtual void sendCommandString(std::string cmd) = 0;
virtual void startAcquisition() = 0;
virtual void stopAcquisition() = 0;
protected:
int _baudRate;
int _numChannels;
};
//-----------------------------------------
// Grandchildren Classes
//=========================================
class CoaxGrabberA : public CoaxGrabber {
//identical public members as CoaxGrabber
//different implementation using
//different low-level API, ex: BitFlow
}
class CoaxGrabberB : public CoaxGrabber {
//identical public members as CoaxGrabber
//different implementation using
//different low-level API, ex: Kaya
}
class LinkGrabberA : public LinkGrabber {
//identical public members as LinkGrabber
//different implementation using
//different low-level API, ex: NationalInstruments
}
class LinkGrabberB : public LinkGrabber {
//identical public members as LinkGrabber
//different implementation using
//different low-level API, ex: Imperx
}
//-----------------------------------------------------
// Finally, my Camera object, nothing too interesting here
//=====================================================
class Camera {
public:
Camera() {
_frameGrabber = NULL;
}
~Camera() {
delete _frameGrabber;
}
void setGrabber(FrameGrabber* newGrabber)
{
delete _frameGrabber;
_frameGrabber = newGrabber;
}
void startAcquisition() {
_frameGrabber.startAcquisiton();
}
void stopAcquisition() {
_frameGrabber.stopAcquisition();
}
int setSensitivity(int sens) {
_frameGrabber.sendCommandString("sens=" + std::to_string(sens));
}
private:
FrameGrabber* _frameGrabber;
};
//-----------------------------------------
// This is why I don't like my Camera object
// the actual end-user interface smells
//=========================================
class CameraGui : QMainWindow
{
public:
void setGrabberType(int type);
void setCoaxGrabberCommAddress(int address);
void setLinkGrabberBaudRate(int rate);
CameraSystem _myCamera;
CoaxGrabber* _myCoaxGrabber;
LinkGrabber* _myLinkGrabber;
};
//---------------------------------------------------------------
//This function smells to me, but I cannot think of any other way
//of course, int type will be enum in actual program.
//===============================================================
void CameraGui::setGrabberType(int type) {
switch (type) {
case 0:
delete _myCoaxGrabber;
_myCoaxGrabber = new CoaxGrabberA();
_myCamera.setGrabber(&_myCoaxGrabber);
break;
case 1:
delete _myCoaxGrabber;
_myCoaxGrabber = new CoaxGrabberB();
myCamera.setGrabber(&_myCoaxGrabber));
break;
case 2:
delete _myLinkGrabber;
_myLinkGrabber = new LinkGrabberA();
_myCamera.setGrabber(&_myLinkGrabber);
break;
case 3:
delete _myLinkGrabber;
_myLinkGrabber = new LinkGrabberB();
_myCamera.setGrabber(&_myLinkGrabber);
break;
}
}
//---------------------------------------------------------------
// this method of setting parameters also smells to me,
// since this data is linked to the Camera object, which
// will have no way of knowing whether the state of its
// framegrabber changed... furthermore, if I change framegrabbers,
// none of the parameter settings (state) will be remembered.
// the user will need to set them all over again.
// the only way I know to circumvent this is to allocate memory for
// every type of framegrabber, and broadcast all state changes to
// all applicable parent grabbers, which will reside in permanent
// memory until the application closes.
//===============================================================
void CameraGui::setCoaxGrabberCommAddress(int address) {
if(myCoaxGrabber != NULL) {
myCoaxGrabber->setCommAddress(address);
}
}
//likewise smell
void CameraGui::setLinkGrabberBaudRate(int rate) {
if(myLinkGrabber != NULL) {
myLinkGrabber->setBaudRate(rate);
}
}
我们将不胜感激任何和所有建议。长话短说,我对 OO 设计模式知之甚少,但这感觉像是一个已解决的问题,我觉得我在重新发明轮子。有没有更好、更成熟的方法来实现我正在尝试做的事情?
【问题讨论】:
-
为什么是“类”而不是“类”?是否有一些特殊的“#define class Class”?
-
不,我只是在将所有内容输入窗口时搞砸了。可能是通过复制/粘贴传播的一个错误。我应该仔细检查我的代码。这些都不会编译,它只是为了让我大致了解我想要实现的目标。长话短说吧,应该是小写的
-
好问题 - 为什么会被否决?
-
我很想将所有配置数据存储在 property map (
std::map<std::string, std::string>) 中,并让每个Graber类型将其配置信息转换为相关类型 (或添加一些通用转换函数)。然后每个Grabber类型可以报告它需要为用户virtual std::vector<std::string> getPropertyList() const = 0;设置哪些属性名称,因此GUI知道要请求什么以及要设置什么属性。 Example Property Map.
标签: c++ user-interface inheritance design-patterns