在C ++中使用名称空间的最佳做法


38

几个月前,我读过Bob叔叔的Clean Code,它对我编写代码的方式产生了深远的影响。即使看起来他在重复每个程序员都应该知道的事情,将它们放在一起并付诸实践确实可以使代码更简洁。特别是,我发现将大型函数分解为许多微型函数,并将大型类分解为许多微型类非常有用。

现在问这个问题。本书的示例全部使用Java,而过去几年我一直在使用C ++。干净代码中的想法如何扩展到Java中不存在的名称空间的使用?(是的,我知道Java程序包,但是并不是完全一样。)

将创建许多微小实体(每个都有明确定义的责任)的想法应用于命名空间是否有意义?一小组相关类是否应该始终包装在命名空间中?这是管理拥有许多小类的复杂性的方法,还是管理大量名称空间的成本过高?

编辑:在有关包装原则的Wikipedia条目中回答了我的问题。


7
另一个关于开发人员的真实问题的示例已经结束。如果这不是stackexchange网站要询问的开发人员最佳实践,那是什么?
Sam Goldberg 2013年

@SamGoldberg:越来越好。在这里,我找到了一个很好的答案:en.wikipedia.org/wiki/Package_Principles。我发布了此答案,并由主持人删除了它,因为我只是发布了链接,而没有时间复制/粘贴内容。
Dima

1
我认为,我对此问题的唯一批评是,而不是在最后提出多个问题,而是将其总结为一个问题,例如:“确定项目应位于相同名称空间还是不同名称空间的标准是什么? ”。
山姆·戈德堡

Answers:


22

(我没有阅读过“ 干净代码”,对Java也不太了解。)

将创建许多微小实体(每个都有明确定义的责任)的想法应用于命名空间是否有意义?

是的,就像重构为多个类和多个函数一样。

一小组相关类是否应该始终包装在命名空间中?

无需实际回答:是的,您至少应使用一个顶级名称空间。这可以基于项目,组织或您喜欢的任何对象,但是使用很少的全局名称将减少名称冲突。用于将其下所有其他内容分组的单个名称空间仅引入一个全局名称。(除了外部“ C”功能,但这是由于C的互操作性,并且仅影响其他外部“ C”功能。)

一小组相关类是否应该包装在专用于它们的命名空间中 大概。特别是如果您发现自己在这些类上使用公共前缀– FrobberThing,FrobberThang,FrobberDoohickey –您应考虑使用名称空间– frobber :: Thing等。如果它们是较大项目的一部分,则它仍将位于您的根名称空间或其他名称空间下。

这是管理拥有许多小类的复杂性的方法,还是管理大量名称空间的成本过高?

以上面的前缀名称为例,管理frobber :: Thing比FrobberThing更加容易。使用某些工具,例如文档和代码完成,甚至可能更容易。ADL有所不同,但这可以使您满意:关联名称空间中的名称较少,使得ADL更易于理解,您可以使用声明将特定名称注入一个或另一个名称空间。

命名空间别名使您可以在特定的上下文中将较短的名称用于较长的命名空间,这又使更容易使用:

void f() {
  namespace CWVLN = Company_with_very_long_name;  // Example from the standard.
  // In this scope, use CWVLN::name instead of Company_with_very_long_name::name.
  namespace fs = boost::filesystem;  // Commonly used.
}

考虑一下Boost,它有一个根根名称空间,boost和随后的许多子命名空间-boost :: asio,boost :: io,boost ::文件系统,boost :: tuples等,用于各种库。 一些名称被“提升”到根名称空间:

所有定义都在命名空间:: boost :: tuples中,但是最常见的名称通过使用声明提升为命名空间:: boost。这些名称是:tuple,make_tuple,tie and get。此外,ref和cref直接在:: boost命名空间下定义。

与带有“实际”模块的语言的最大区别是使用扁平结构的普遍性,这种情况通常发生是因为这是它的工作方式,除非您花费额外的精力来定义嵌套名称。


+1 @Fred Nurk进行了完整分析,而不是一行回答。您无需阅读本书即可知道问题所在。该注释线程揭示了C ++和Java程序员在本书上可能会有的概念和差异。亚马逊的干净代码评论
Marlon

8

您应该为所有代码使用一个主命名空间。就命名空间而言,这与外部代码有所区别。

在主命名空间中,根据大小和复杂性,您可以打开子命名空间。这是名称在上下文中明确表示某些含义的地方,而相同的名称可能在不同的上下文中使用。

特别是,如果您有一个通用的名称,如FileInfo,这意味着在上下文中有特定的含义,请将其放在名称空间中。

您也可以为此使用类,尽管类是不可扩展的,因此您不能在不修改其标题的情况下向该类添加新的声明。


3

命名空间不是模块的概念,因此我仅在可能发生名称冲突的地方使用它们。


4
不明白你的意思。为什么包装在名称空间中的一组相关类不是模块?
迪马

命名空间内没有任何限制。在模块中,您可以说给定的类,函数或变量只能从模块内部访问。在名称空间中,这不可能是名称的前缀。
Brainlag 2011年

3
看起来我们不同意模块的定义。对我而言,将相关实体组合在一起并具有描述性名称的任何东西都是模块,无论它是否提供封装。
Dima

3
访问限制与模块正交。实际上,您拥有像Python这样的成功系统,这些系统肯定比C ++命名空间更像“模块式”,但是完全没有施加访问限制。
Fred Nurk

我相信这是斯科特·迈耶(Scott Meyer)书中列出的最佳做法之一
拉斐尔,

1

Java有名称空间,只是没有真正使用它们。In javax.swing.* javax是一个命名空间,swing是一个子命名空间。我还没有读过这本书,不知道它对Java包有什么说,但是相同的原理几乎可以直接应用于任何语言的名称空间。

一个很好的启发式方法是,当您发现自己想一遍又一遍地为类键入相同的前缀时,就使用名称空间。例如,我最近编写了一些名为OmciAttribute,OmciAlarm,OmciMe等的类,并意识到我需要将Omci分解为自己的命名空间。


1

我喜欢深名称空间(通常意味着三个级别)。

  • 我有公司名
  • app / util / lib / etc
  • 专案名称/或包装

根据情况,我可能还会再上一层

  • 详细信息(特定于平台的实现详细信息)
  • utils(尚未移动到通用实用程序的实用程序对象)。
  • 无论我需要什么
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.