具有公共成员对象的类组合

时间:2016-06-15 14:27:31

标签: c++ oop

我想找出设计程序功能的最佳方法。

该程序的主要组成部分是Camera类。此Camera对象表示真实摄像机的程序用户界面,该摄像机通过帧抓取卡与计算机连接。摄像机类可以链接到帧抓取器,启动和停止采集,还可以改变/访问许多不同的摄像机属性。当我说很多时,我说的是250多个独特的命令。通过帧抓取器向物理相机发送串行字符串,向相机发出每个唯一命令。每个命令可以被认为是三种类型之一。动作,查询和值。

动作命令不需要等号,例如“重置”,“打开”,“关闭”

您可以获取但未设置的查询通常与值相关联。例如“温度=?”,“sernum =?”,“maxframerate =?”命令会导致相机发回信息。这些值不能改变,因此“温度= 20”会导致错误。

值是您可以获取和设置的值,通常与值相关联。例如“framerate = 30”和“framerate =?”是两个独特的命令,但我认为基本字符串“framerate”是一个值命令类型,因为它可以被变异和访问。

250个独特的命令可以减少到~100个CameraActions,CameraQuerys和CameraValues。我没有在我的Camera类中使用250个方法,而是想到了编写命令对象而不是单独的setter,getter和actions。命令字符串可以在构造函数中提供,也可以使用setter重置。然后我可以编写一个包含所有可用命令的CameraCommands对象,并将其作为公共成员提供给我的相机。

//CameraAction.h =============================================
class CameraAction {
public:
  CameraAction(std::string commandString, SerialInterface* serialInterface);
  void operator()() { _serialInterface->sendString(_commandString); }

private:
  SerialInterface* _serialInterface;
  std::string      _commandString;

}; 


//CameraValue.h =====================================================
class CameraValue {

public:

  CameraValue(std::string commandString, double min, double max, SerialInterface* serialInterface);

  void set(double value)
  {
    if(value > _maxValue) { throw std::runtime_error("value too high"); }
    if(value < _minValue) { throw std::runtime_error("value too low"); }
    std::string valueString = std::to_string(value);
    _serialInterface->sendString(_commandString + "=" + valueString);
  }

  double get()
  {
    std::string valueString = _serialInterface->sendString(_commandString + "=?");
    return atof(valueString.c_str());
  }

private:

  SerialInterface* _serialInterface;
  std::string      _commandString;
  double           _minValue;
  double           _maxValue;

};  


//CameraCommands.h ===================================================
class CameraCommands {

public:
  CameraCommands();
  CameraAction reset;
  CameraQuery  temperature;
  CameraValue  framerate;
  CameraValue  sensitivity;
  //... >100 more of these guys

};


//Camera.h ===========================================================
class Camera {
public:
  Camera();
  CameraCommands cmd;
  void startAcquisition();
  void stopAcquisition();
  void setDataBuffer(void* buffer);
  void setOtherThing(int thing);
};

以便用户可以执行以下操作:

Camera myCamera;
myCamera.cmd.reset();
myCamera.cmd.framerate.set(30);
myCamera.cmd.sensitivity.set(95);
double temperature = myCamera.cmd.temperature.get();
myCamera.startAcquisition();

等...

这里的主要问题是我暴露了公共成员变量,这应该是一个巨大的禁忌。我当前的对象设计是否合乎逻辑,或者我应该简单地实现250个setter和getter以及100个setter和getter来改变最小和最大可设置值。

这对我来说似乎很麻烦,因为还有许多与Camera对象关联的setter / getter与用户命令无关。用户界面提供方法的范围(cmd),以便用户知道相机中是否有物理变异,或者只是在程序对象中进行变异(其他方法),这很好。有没有更好的方法来设计我的程序?

3 个答案:

答案 0 :(得分:1)

你基本上描述了一个有趣的层次结构:

Command - &gt; Query - &gt; Value

  • Command保存作为命令文本的字符串; 它还可以为其子女提供protected Send()方法。
  • Query还包含一个(protectedint变量(或其他),您可以立即get()和/或operator int()或{{} 1}}来自相机;
  • query()Value和/或set()命令添加到operator =(int)

Query的构造函数(特别是)可以包含Valuemin

max对象可以有多个Camera成员:

public

通过这样组织,然后:

  • 变量的用户无法提出不可能的请求 - 没有方法可以这样做;
  • class Camera { private: // Classes that no-one else can have! class Command; friend Command; #include "Camera.Command.inc" class Query; friend Query; #include "Camera.Query.inc" class Value; friend Value; #include "Camera.Value.inc" public: // Variables using above classes Command reset; Command open; // Maybe make this one private, for friends? Command close; // Ditto? Query temperature; Query sernum; Query maxFrameRate; Value frameRate; private: // Variables SerialPort port; // Allow Command and co. access to this }; // Camera query()方法隐藏了与物理相机连接的机制。

您会注意到我在set()课程的中间添加了#include "Camera.XXX.inc"。注意:

  1. 它不会使Camera类与这些子类的定义混淆 - 但C ++编译器需要它们才能使用它们,所以你需要将它们放在那里。如果你想知道他们做了什么,只需打开文件!
  2. 我向他们提供了Camera扩展程序,因为它们已被“包含”在.inc文件中:它们并不是唯一的标题文件。

答案 1 :(得分:0)

您可以使用一个或多个结构对“设置”进行分组,然后公开一种方法来设置它们:

typedef struct settings{
  int setting1;
  int setting2;
}MySettings;

class Myclass{
 private :
   int setting1;
   int setting2;

 public Myclass(MySettigs *settings)
{
  if(null != settings){
     setting1=settings->setting1;
     setting2=settings->setting2;
  }
}

public void ChangeSettings (MySettings *setting){
  if(null != settings)
  {
     setting1=settings->setting1;
     setting2=settings->setting2;
  }
}

public void TakeSettings (MySettigs *settings){
  [copy local variables into the passed struct]
}

我强烈建议在对象处于“可操作”状态时更改设置时要小心。在另一个线程正在使用设置时,您可能会处于未定义状态。

答案 2 :(得分:0)

在你提到的设计中,我不认为通过作文揭露公众成员是一个很大的禁忌。

当暴露公众成员时,最大的禁忌是不安全访问您的班级内部。

一个例子是允许公共访问CameraValue::_maxValue。用户可以将该值更改为任何内容,从而导致各种未定义的行为。

根据我的设计,我不会拥有CameraCommands成员,因为从它的外观来看,除了间接水平之外,它不会添加任何其他内容。

我会将所有CameraActionCameraValue成员添加为相机类的一部分,或者继承它们。

这样的事情:

CameraCommands合并到Camera

class Camera 
{
public:
  Camera();

  CameraAction reset;
  CameraQuery  temperature;
  CameraValue  framerate;
  CameraValue  sensitivity;
  //... >100 more of these guys

  void startAcquisition();
  void stopAcquisition();
  void setDataBuffer(void* buffer);
  void setOtherThing(int thing);
};

CameraCommands继承到Camera

class Camera : public CameraCommands
{
public:
  Camera();

  void startAcquisition();
  void stopAcquisition();
  void setDataBuffer(void* buffer);
  void setOtherThing(int thing);
};

您甚至可以为CameraValue等提供一些运算符,以便您可以通过赋值(operator=)设置值,并通过隐式转换(operator T)或取消引用来获取值(operator*):

template<typename T>
class CameraValue
{
public
    CameraValue(SerialInterface*, std::string cmd);

    CameraValue& operator=(const T& val)
    {
        _val = val;
        std::string val_str = std::to_string(_val);
       _ser_ifc->sendString(_cmd + "=" + val_str);            
    }

    const T& get() const
    {
        return _val;
    }

    // implicit access to _val
    operator const T&() const
    {
        return _val;
    }

    // dereference operator to access _val
    const T& operator*() const
    {
        return _val;
    }
private:
    T _val;
    SerialInterface* _ser_ifc;
    std::string      _cmd;
};

然后在课程中使用CameraValue,如下所示:

using CameraFramerate = CameraValue<int>;

CameraFramerate framerate;

上述技术为(IMO)提供了Camera的更可组合使用,例如:

Camera camera;

// setting values
camera.framerate = 30;
camera.sensitivity = 95;

// getting values
int framerate =  camera.framerate; // uses operator T&()
int framerate = *camera.framerate; // uses operator*()

这里的关键点是Camera::framerate等不允许任何可能改变您的相机类别的访问权限。内部状态以不确定和/或不安全的方式。