【问题标题】:Are mutually-dependent child/parent namespaces a code smell?相互依赖的子/父命名空间是代码异味吗?
【发布时间】:2010-11-02 21:14:57
【问题描述】:

我最近正在查看我的主要个人项目的一些依赖关系图,我注意到嵌套命名空间中的对象之间存在相互依赖关系。例如,我在MyNamespace.Foo 中有一个对象,它在MyNamespace.Foo.Interfaces 中实现了一个通用接口,该对象作为接口中的通用参数。

namespace MyNamespace.Foo
{
    internal class Foo : MyNamespace.Foo.Interfaces.IFoo<Foo>
    { }
}

在这种情况下。依赖分析工具(VS2010 beta)合理地认为接口的通用“实例化”(为了讨论,我知道这不是c++)是接口命名空间的成员,然后依赖于其父命名空间。

经过我的一些考虑,我或多或少得出结论,在我的特定情况下,我现有的设计是一种代码气味。我应该将 Interfaces 命名空间合并到父 Foo 命名空间中。 (如果我希望客户端通过IFoo 使用Foo,那么要求客户端向下钻取一个额外的层到接口命名空间是愚蠢的。)但是在一般情况下这是真的吗?

应该如何管理命名空间间的依赖关系?应该“更广泛”的命名空间(如MyNamespace.Foo 通常依赖于“更窄”的命名空间(如MyNamespace.Foo.Interfaces),还是应该更窄的命名空间依赖更广泛的命名空间?还是有更好、更微妙的答案?

【问题讨论】:

    标签: .net design-patterns namespaces dependencies


    【解决方案1】:

    在关于您的示例的特定情况下,我会将 Interfaces 命名空间合并到父命名空间中。

    一般来说,我认为更窄的命名空间应该依赖于更广泛的类或接口,或者是共享父命名空间的子类或接口。第二种情况是典型的,如果您安排了命名空间,以便模型命名空间具有共享类或接口,这些类或接口描述了您的代码试图解决的问题的模型。

    我还应该注意,我认为这些规则不一定适用于第三方依赖项。例如,依赖于代码中 Spring.NET 中狭窄命名空间的代码并不构成代码异味。

    【讨论】:

      【解决方案2】:

      如果您想将接口与实现分开,可以使用并行的 MyNamespace.Foo.Interfaces 和 MyNamespace.Foo.Implementation 命名空间。

      默认情况下,命名空间似乎等同于包或程序集:因此 FooBar 将分别是 foo.dllbar.dll 的命名空间。

      如果我想要更高级别的分组,我会在命名空间中添加前缀:例如,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 的代码除外)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-02-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多