gpt4 book ai didi

C++类设计: class or functions in unnamed namespace or private class method?

转载 作者:太空狗 更新时间:2023-10-29 21:20:14 24 4
gpt4 key购买 nike

我正在扩展现有类别的新功能,但我对使用哪种设计解决方案存疑。有几种,每种都有优点和缺点。我的情况是这样的:我有一个具有特殊格式的文件头,我要读取并保存它。有一个名为 FileHeader 的类,它已经实现了一些从/到流的序列化和一些其他功能。我的任务列表中的一项是添加某个时间戳功能。时间戳应读取/存储为自 1994 年 1 月 1 日 00:00:00 以来的秒数。然而,FileHeader 类将日期和时间存储在两个单独的变量中。因此,我需要编写从/到秒到日期和时间的转换。问题是该功能应该位于何处。我使用 secondsPerDay (60*60*24) 和 dateOrigin (1/1/1994) 作为常量。

我看到有以下选项:

A) 将转换实现为 FileHeader 类的私有(private)方法。 secondsPerDay 和 dateOrigin 将是该类的静态私有(private)常量。

//fileheader.h
class FileHeader
{
private:
static const unsigned secondsPerDate = 60 * 60 * 24;
static const Date dateOrigin;
const Date &m_date;
const Time &m_time;
unsigned convertToSeconds() const; // convert m_date and m_time to seconds
void fromSeconds(unsigned secs); // convert and store to m_date and m_time
public:
void saveToStream(Stream &s) const;
void restoreFromStream(const Stream &s);
//... other methods
}

//fileheader.cpp
const Date FileHeader::dateOrigin = Date(1994, 1, 1);

这很简单。但我不喜欢的是,它给本已相当繁重的类(class)增加了更多的责任。你知道规则:一个类(class) = 一个职责。例如维护会很困难。如果有人决定将秒更改为分钟或其他任何内容,他会重写这些方法,但如果不够小心,可能会保留静态常量 secondsPerDay,尽管它不再需要了。等等。此外,我不喜欢必须更新头文件这一事实,尽管它只影响实现细节。

B) 仅在 .cpp 文件中的未命名命名空间中执行实现,并使用普通函数和静态变量:

namespace
{
const unsigned secondsPerDay = 60 * 60 * 24;
const Date dateOrigin = Date(1994, 1, 1);
unsigned dateTimeToSeconds(const Date &d, const Time &t) ...
Date secondsToDate(unsigned secs) ...
Time secondsToTtime(unsigned secs) ...
}

然后 FileHeader 的保存和恢复方法将调用这些函数。好吧,我更喜欢它。我没有弄乱标题,类(class)的 FileHeader 责任没有增长。但是,如果有人决定更改算法以使用分钟而不是秒,他可以更改函数,但如果不小心,他会留下不必要的 secondsPerDay 静态变量,即使不再需要它也是如此。

C) 在 FileHeader.cpp 中使用未命名的命名空间并在其中使用专用类。

namespace 
{
class TimeConverter
{
private:
static const unsigned secondsPerDay = 60 * 60 * 24;
static const Date dateOrigin;
public:
static unsigned secondsFromDateTime(const Date &date, const Time &time) //implementation here...
static Date dateFromSeconds(unsigned seconds) //implementation here...
static Time timeFromSeconds(unsigned seconds) //implementation here...
};
const Date TimeConverter::dateOrigin = Date(1994, 1, 1);
}

然后 FileHeader 保存和恢复将调用这些静态方法,例如

m_date = TimeConverter::dateFromSeconds(secs);
m_time = TimeConverter::timeFromSeconds(secs);

我个人选择了这个解决方案。它不会弄乱标题,它在视觉上限制了静态变量的范围,因此如果有人将 TimeConverter 的实现从秒更改为分钟,他很可能不会留下不必要的静态变量 secondsPerDay ...目前TimeConverter 不被任何其他类(仅 FileHeader)使用,但如果更改它,它可以很容易地移动到它自己的头文件和源文件中。

在编写代码时,我意识到这是我扩展现有类的新实现细节功能的常用方法。因为我经常这样做,所以我很好奇其他人在使用什么以及为什么使用。根据我的经验,95% 的开发人员使用选项 A 并扩展类。那么问题来了:

  • 还有其他好的和有用的选择吗?

  • 我是否遗漏了使用这些选项的某些重要方面或含义?

更新:根据以下答案之一的建议,我特此提出选项 D:

namespace TimeConverter
{
const unsigned secondsPerDay = 60 * 60 * 24;
const Date dateOrigin = Date(1994, 1, 1);
unsigned secondsFromDateTime(const Date &date, const Time &time)
{
return (date - dateOrigin) * secondsPerDay + time.asSeconds();
}

Date dateFromSeconds(unsigned seconds)
{
return dateOrigin + seconds / secondsPerDay;
}

Time timeFromSeconds(unsigned seconds)
{
return Time(seconds % secondsPerDay);
}
}

接下来是一个问题——D 比 C 好在哪里,反之亦然。有什么优点和缺点?

最佳答案

就我个人而言,我会选择选项 B。如果我需要重新使用该功能,我会将其改编为 C。但我认为为每一件小事创建一个类会导致过多的膨胀和样板。我更喜欢在需要时进行抽象,而不是在...之前... YAGNI 的变体.选项 B 在同一位置定义和使用功能,这样更易​​于阅读。另外,正如您所说,它不会使头文件困惑。

关于C++类设计: class or functions in unnamed namespace or private class method?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25053473/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com