基础C++设计
Basic C++ Design
我有一个关于C++类设计的问题。我经常面临这样的小问题,我想得到一些关于什么更容易被接受的建议。
我有一些类通过UDP监控某些设备的温度。如果设备接收到一个数据包,它将向stdout打印"x\n"以显示它接收到了什么。然后是检查数据包中的数据,并验证数据是否显示设备温度过高。如果它太高,我必须调用一些函数。如果不是,我必须调用其他函数。
我不确定我是否应该这样做:
enum temperature {TEMPERATURE_FINE, TEMPERATURE_EXCEEDED};
int main(int argc, char* argv[])
{
std::vector<std::string> args(argv+1, argv + argc);
if(!args.size())
cout << "No parameters entered.n";
else
{
CTemperatureMonitor tempMonitor(args);
if(tempMonitor.MonitorTemperature() == TEMPERATURE_EXCEEDED)
tempMonitor.ActivateAlarm();
else
tempMonitor.DisableAlarm();
}
return 0;
}
其中tempMonitor.MonitorTemperature()调用std::cout << "xn"
。因此std::cout << "xn"
被内置到类中。
或者:
enum temperature {TEMPERATURE_FINE, TEMPERATURE_EXCEEDED};
int main(int argc, char* argv[])
{
std::vector<std::string> args(argv+1, argv + argc);
if(!args.size())
cout << "No parameters entered.n";
else
{
CTemperatureMonitor tempMonitor(args);
temperature tempExceeded = tempMonitor.MonitorTemperature();
std::cout << "xn";
if(tempExceeded == TEMPERATURE_EXCEEDED)
tempMonitor.ActivateAlarm();
else
tempMonitor.DisableAlarm();
}
return 0;
}
其中CCD_ 3不包括在该类中。
std::cout << "xn"
必须出现在调用CTemperatureMonitor::ActivateAlarm()
和CTemperatureMonitor::DisableAlarm()
之前。
我知道这可能看起来很小,也很简单,但我经常想知道到底什么应该成为课堂的一部分。该类是否应该输出到stdout?我做一个还是做另一个有什么区别吗?我是不是太迂腐了?
此外,顺便说一句,我知道全局变量被认为是糟糕的做法。我在main和class中都使用了温度枚举。我应该声明两次,一次在main中,一次是在CTemperatureMonitor类中,还是全局声明一次?虽然这个问题看起来相当具体,但它实际上会为我澄清很多其他事情
谢谢。
首先,我想指出的是,项目有不同的规模,根据规模(和关键性),建议实际上会有所不同。因此,首先有一条经验法则:
您放置的"框架"(Logger、Option Parser等)的大小可能不应超过整个程序的10%。在这一点之后,这就太过分了。除非这是练习的目标!
话虽如此,我们可以开始看看你的实际问题。
此外,顺便说一句,我知道全局变量被认为是糟糕的做法。我在main和class中都使用了温度枚举。我应该声明两次,一次在main中,一次是在CTemperatureMonitor类中,还是全局声明一次?
实际上,您弄错了变量和类型temperature是一种类型(枚举类型)。
通常,类型被用作程序各个部分之间的桥梁,为此,所有这些部分共享相同的类型定义是很重要的。因此,对于类型,实际声明两次是不好的做法。
此外,并非所有的全球都是邪恶的。全局变量是(共享状态),但全局常量很好,通常扮演类似于类型的角色。
我知道这可能看起来很小,也很简单,但我经常想知道到底什么应该成为课堂的一部分。该类是否应该输出到stdout?我做一个还是做另一个有什么区别吗?我是不是太迂腐了?
有两种输出:
- 日志记录输出,用于在遇到问题时诊断问题
- 真实输出,这是程序所做的
根据程序的不同,您可能同时拥有或没有。
从迂腐的角度来看,你通常不喜欢把它们混合在一起。例如,您可以完美地将日志记录发送到一个文件,或者当它很严重时发送到stderr
,并使用stdout
作为"有用"的东西。
这实际上在一定程度上推动了设计,因为您需要两个接收器:每个输出一个。
由于您有一个非常简单的程序,最简单的方法可能是在构造时简单地将两个不同的std::ostream&
传递给您的类。或者,更简单的是,只需要两个泛型函数并使用(邪恶的)全局变量。
在较大的程序中,您可能会设计一个Logger类,该类将具有各种日志级别,并提供特定的宏来注册(自动)日志行的函数名、文件名和行号。您可能还有一个轻量级的日志记录机制,允许您在Release构建中禁用DEBUG
/DEV
级别的日志记录。
单一抽象级别的原则有利于用相同的方法进行所有I/O,而不是在高抽象级别和低抽象级别进行一些I/O。
换句话说,如果你相信这一原则,那么通过cin/cout将输入和输出保持在同一方法中,而不是显示和隐藏一些是一个好主意。它倾向于在每个类中提供可读性更强、依赖性更少的代码。
根据单一责任原则,第二种选择是首选(任何类都应该只有一个责任,即监测您的情况下的温度,而不是输出结果),尽管您可能希望设置另一个类来处理温度监测结果(例如将结果写入某个日志文件或其他文件)。
以某种方式记录有关程序的信息是正常的
这种方式在全球范围内也是很正常的。
否则,在调用方法时,事情就会变得过于复杂
你唯一应该做的就是:
有一个logger类(或使用现有的logger类),可以将其输出流设置为您选择的任何值(包括std::out和一个不打印任何内容的空流)
最终,要有一个可以隐藏在#define后面的记录器,这样它就不会减慢在Release模式下运行的代码。
在我看来,在这种情况下,您不应该将cout包含在类中,因为有时以后您需要输出到文件中,或者根本不输出。因此,如果cout没有放在类中,您将有机会在没有任何更改的情况下重用类代码。
两者都没有。main的职责是用命令行参数启动应用程序并给出返回值。其他一切都不应该存在。您可能想看一本书,如"对象设计、角色、责任和协作"
- 设计一个只能由特定类实例化的类(如果可能的话,通过make_unique)
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 将寄存器设计成可由C和C++访问的外设的最佳实践
- 询问在设计我的手臂模拟器功能表示格式1
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践
- 资源管理设计模式
- 多态杆件变量 - 类设计
- 如何设计具有不同类型的通知和观察器的观察者模式?
- 如何使用要传递给 mt19937 的可选随机种子参数设计函数
- 设计将引用元素移动到开头的数据结构.C++
- С++ wxWidgets:代码架构,设计原则和模式
- 用于在回调中调用解析器的设计模式
- 在设计 SDK 时,我是否应该在 C++ 头文件中完全隐藏内部类?
- 需要为 C++ 中的以下问题设计递归算法
- 使用 SFINAE 设计模板方法
- C++,您能否设计一种数据结构,将指针保存在连续内存中并且不会使它们失效?
- 设计帮助 - 为不同类型的消息处理通用接口的设计模式
- C++模板编程设计问题 - 根据输入文件返回不同的类型
- 在这种情况下我应该使用哪种设计模式
- C++中物体改变识别的设计模式?