我最近查看了我的主要个人项目的一些依赖图,我注意到我在嵌套命名空间中的对象之间存在相互依赖关系。例如,我在MyNamespace.Foo
中有一个对象,它在MyNamespace.Foo.Interfaces
中实现了一个通用接口,该对象作为接口中的泛型参数。
namespace MyNamespace.Foo
{
internal class Foo : MyNamespace.Foo.Interfaces.IFoo<Foo>
{ }
}
在这种情况下。依赖分析工具(VS2010 beta)合理地认为接口的通用“实例化”(为了讨论,我知道这不是c ++)是Interfaces命名空间的成员,然后依赖于其父命名空间。
经过我的一些考虑,我或多或少得出的结论是,在我的特定情况下,我现有的设计是代码嗅觉。我应该将Interfaces
命名空间合并到父Foo命名空间中。 (如果我希望客户端通过Foo
使用IFoo
,那么要求客户端将额外的层向下钻取到接口命名空间是很愚蠢的。)在一般情况下这是否正确?
如何管理命名空间间依赖关系? “更广泛”的名称空间(如MyNamespace.Foo
)通常应该依赖于“较窄”的名称空间(如MyNamespace.Foo.Interfaces
),还是较窄的名称空间应该依赖于更广泛的名称空间?还是有更好,更微妙的答案?
答案 0 :(得分:2)
在关于您的示例的特定情况下,我会将Interfaces
命名空间合并到父命名空间中。
一般来说,我认为较窄的命名空间应该依赖于来自更广泛的类或接口,或者是共享父命名空间的子类。第二种情况是典型的,如果您安排了名称空间,以便模型名称空间具有共享类或接口来描述您的代码试图解决的问题的模型。
我还应该注意,我不认为这些规则必然适用于第三方依赖。例如,根据代码中Spring.NET中的狭窄命名空间中的代码,不构成代码气味。
答案 1 :(得分:2)
如果要将接口与实现分开,可能是MyNamespace.Foo.Interfaces和MyNamespace.Foo.Implementation命名空间。
默认值似乎是命名空间等同于包或程序集:因此Foo
和Bar
分别是foo.dll
和bar.dll
的命名空间。< / p>
如果我想要更高级别的分组,我会在命名空间中添加前缀:例如MyCorp.Server.Foo
是MyCorp生成的服务器端foo.dll
的命名空间。
请注意,我正在添加前缀,而不是后缀:所以MyCorp.Server.Foo
而不是Foo.Server.MyCorp
。这些结构化名称空间对应于包含源代码和项目的文件夹/目录结构。
默认情况下,程序包中的所有文件都具有相同的名称空间(例如foo.dll
中的所有代码都属于MyCorp.Server.Foo
名称空间)。如果我确实添加了后缀,则会将该代码隐藏在程序集的其余部分中。例如,MyCorp.Server.Foo.EditorTransactions
命名空间中的代码存在于foo.dll
中,但foo.dll
中的大多数其他代码都看不到(除了明确使用MyCorp.Server.Foo.EditorTransactions
的代码之外)。