Paw*_*arz 16 c++ design-patterns units-of-measurement
我正在研究游戏引擎,目前我不得不设计IO系统.我已经做到了,引擎本身不处理任何文件格式,而是让用户通过创建*.dll具有适当命名函数的文件来实现他想要的任何东西.虽然这本身并不是什么大问题,但我主要担心的是在发动机使用过程中可能会出现的影响.
我设计了一个简单的resource接口作为用户可以想到的所有东西的基类,我试图通过创建专用于常见数据类型的简单子类来扩展它,因此用户不必实现基础知识由他本人(目前我在想audio,image,data和mesh).从audio课堂开始,我偶然发现了一个特殊的问题,同时试图决定应该以什么类型存储有关采样率的信息.通常的单位是赫兹,所以我决定把它变成一个unsigned int.
但是这里有一点问题 - 如果用户试图用千赫兹设置它会怎么样?让我们假设一些抽象文件格式可以暂时将它存储在两个单元中.我已经创建了一个简单的包装类来命名单元类型:
class hertz{
private:
unsigned int value;
hertz(){};
public:
operator unsigned int();
hertz(unsigned int value);
};
Run Code Online (Sandbox Code Playgroud)
并决定让用户也使用kHz:
class kilohertz{
private:
float value;
kilohertz(){};
public:
operator hertz();
kilohertz(float value);
};
Run Code Online (Sandbox Code Playgroud)
虽然audio类中的函数允许用户设置采样率,但声明为track& samplingRate(units::hertz rate);.用户必须通过明确说出他正在使用的数量级来调用它:
someAudioFile.samplingRate(hertz(44100));
someAudioFile.samplingRate(kilohertz(44.1));
Run Code Online (Sandbox Code Playgroud)
我的问题是:
是否有更好的方法迫使用户以简单而优雅的方式使用测量单元?一个设计模式可能,或者一些巧妙使用typedef?
另请注意,在创建引擎的过程中,我可能需要更多与Hertz不兼容的单元.从我的头脑 - 我可能希望用户能够通过做units::rgb(123,42,120)和设置像素颜色units::hsl(10,30,240).
我已经尝试寻找一个可行的答案并且只找到了这个问题,但OP只需要数量级而不确保单位与其他单位不兼容.
另请注意我使用旧C++版本,而不是C++11.虽然在任何版本中发布有效的解决方案都很棒,但如果我也可以使用它会很好:)
con*_*gus 27
我知道你提到过你没有使用C++ 11,但是其他人可能会看到这个问题,所以这里是使用用户定义文字的C++ 11解决方案:
#include <iostream>
using namespace std;
class Frequency
{
public:
void Print() const { cout << hertz << "Hz\n"; }
explicit constexpr Frequency(unsigned int h) : hertz(h) {}
private:
unsigned int hertz;
};
constexpr Frequency operator"" _Hz(unsigned long long hz)
{
return Frequency{hz};
}
constexpr Frequency operator"" _kHz(long double khz)
{
return Frequency{khz * 1000};
}
int main()
{
Frequency(44100_Hz).Print();
Frequency(44.1_kHz).Print();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
44100Hz
44100Hz
Run Code Online (Sandbox Code Playgroud)
Boost"Units"库非常适合这种类型的东西.
http://www.boost.org/doc/libs/1_55_0/doc/html/boost_units.html
您可以使用工厂设计模式来完成所需的工作。您可以使用私有构造函数和几个静态方法创建频率类,这些方法将根据用户要使用的单位来构造对象。通过使构造函数保持私有状态,用户被迫显式声明其单元,从而降低了用户出错的可能性。
#include <iostream>
using namespace std;
class frequency
{
public:
static frequency hertz(int hz)
{
return frequency(hz);
}
static frequency kilohertz(double kHz)
{
return frequency(kHz * KHZ_TO_HZ);
}
static frequency rpm(int rpm)
{
return frequency(rpm * RPM_TO_HZ);
}
int hz()
{
return m_hz;
}
private:
static const int KHZ_TO_HZ = 1000;
static const int RPM_TO_HZ = 60;
frequency(int hz) : m_hz(hz)
{
}
int m_hz;
};
int main()
{
wcout << frequency::hertz(44100).hz() << "Hz" << endl;
wcout << frequency::kilohertz(44.100).hz() << "Hz" << endl;
}
Run Code Online (Sandbox Code Playgroud)