为接口和实现提供单独的名称空间值得吗

Is it worth it to have separate namespaces for interfaces and implementations?

本文关键字:空间 值得 单独 接口 实现      更新时间:2023-10-16

为接口和实现提供单独的名称空间值得吗?

Stroustrup在他的C++书(第四版)中的建议是,我们应该使用单独的名称空间用于接口和实现。更有经验的人能说点什么吗在这个问题上?我的意思是,这听起来不错,但它真的实用吗现实世界的项目?

名称空间告诉定义属于谁。当然,接口属于与实现不同的组是有意义的;这就是接口的全部意义,关注点的分离。

在那些需要大量实现的代码中(比如Boost中的一些元编程怪物),一眼就能发现哪些代码可以直接使用,哪些代码可以安全地忽略,这可能很有用。库的detail命名空间中的代码被视为"内部"代码,因此当您在堆栈跟踪中看到detail符号时,不需要花费时间搜索文档。

我不会说它有巨大的好处,当然在一般情况下也不是这样,但既然它不会造成任何伤害,你还不如保持整洁和隔离。

在现实世界的项目中有意义吗?

是的,例如在boost中,它被广泛使用。以boost::shared_ptr为例。当我看到namespace detail时,我立刻知道我不必太仔细地研究那个代码段,除非有错误消息告诉我要这样做(即使这样,也很可能是我的错)。

强制性设计的现实世界启发的例子

我想你知道如何驾驶汽车。有很多接口:方向盘、油门/刹车/离合器踏板、显示器等等。你有兴趣使用这些接口,毕竟,这就是你使用汽车的方式:

namespace the_company{
struct wheel{
void turnLeft(deg);
void turnRight(deg) { turnLeft(-deg); }
};
struct pedal{
void tap();  
void press_completely_till_something_happens(); 
//!< might deadlock if using break and car isn't moving
};
struct display{
so_many_colors lookat();
};
}

为了这个例子,我们将把它们组合在一起作为一辆车,但将它们拆分成不同的名称空间不仅对OOP实用。

namespace the_company{    
struct car{
public:
wheel & getWheel();
pedal & getBreakPedal();
...
};
}

我们对car有什么期望?我们可以期待我们可以使用汽车的车轮或踏板,它会起作用:

car myCar;
myCar.getGasPedal().press_completely_till_something_happens();
// OH GOD; WHAT HAVE I DONE!?
myCar.getWheel().turnLeft(360);
myCar.getBreakPedal().press_completely_till_something_happens();
// Shew. That was close.

我们完全可以使用car。顺便说一句,我们没有把wheel放在car中,因为我们公司可能会生产其他使用轮子的东西,比如船、卡车、人造飞机、阀门和其他非车辆的东西,而display可能会被更多不同的东西使用(手机、显示器、电视,你能想到的)。

然而,为了让汽车真正运转起来,它必须有一个发动机。由于发动机是一些相当复杂的机器,我们将它们隐藏在hood:之下

namespace the_company{
namespace hood{
struct engine{
// heavily optimized code
// not so nice interface anymore
// maybe not even documentated
...
};
}
}

engine是一个野兽,它是可扩展的,可以适用于任何车辆或重型机械,您的公司在优化方面投入了大量精力。现在,每当车主的发动机出现问题时,他可以简单地查看hood并检查出了什么问题。

但事实上,它隐藏在某个东西后面,从一开始就告诉用户,他应该知道自己要做什么。如果他不理解金属/代码,他应该向他的服务维护/支持部门寻求帮助。

此外,engine可能会发生变化,甚至被完全删除,因为我们公司发明了fusion_engine,这会带来更好的利润。

这就是namespace detail对我的意义:复杂的细节,可能会改变,甚至可能只对最初的维护人员有意义。但没关系。它不是接口的一部分。