【问题标题】:Where should class Interfaces be placed in a .NET class library? [closed]类接口应该放在 .NET 类库中的什么位置? [关闭]
【发布时间】:2012-02-06 16:40:12
【问题描述】:

我很好奇开发人员关于类接口应该放置在 .NET 类库中的什么位置的意见/实践。它们是否应该包含在解决方案中自己的专用库中,例如 MyCompany.AccountPackage.Interfaces?

他们是否应该有自己的命名空间,例如MyCompany.AccountPackage.MasterAccounts.Interfaces?

任何其他想法/意见表示赞赏?

是否有任何好的指南来演示如何构建 .Net 库(甚至更好的解决方案),一般显示哪些类/接口通常应该在标准库中公开。

谢谢, d.

【问题讨论】:

  • 在我做过的所有课程和教程中,界面总是放在班级的正上方
  • 不会给他们自己的命名空间或库。正如 .NET Framework 设计指南 中的一位超级聪明人所说(我不记得是哪一个,而且我的书不方便),除非您 提供该接口的具体实现。因此,只需将接口放在与该实现相同的命名空间中即可。
  • 也就是说,我实际上会努力尽量减少您编写的接口数量,而不是尽可能选择抽象类。这为您提供了接口的几乎所有优点,同时还允许您为许多方法提供默认实现。但这确实是主观的;我不确定这是否适合 SO。
  • @CodyGray 相信它还继续说除非它也被消耗,否则不要发货(他们甚至引用 ICloneable 作为一个坏例子)

标签: c# design-patterns interface


【解决方案1】:

简答:

接口应该靠近它们的实现位置。

至少有一些 BCL 这样做 - 例如,IEnumerable<T> 位于 System.Collections.Generic 命名空间中。


答案稍长:

这取决于接口的用途。

是否为第三方提供插件接口(a-la 提供者模型或 MEF)?

如果是这样,一个单独的程序集是有意义的,所以第三方只需要导入这个程序集。

它是内部的,用于测试和 IoC 目的吗?

我认为保持它接近实现是有意义的,在组织上并有助于使代码与接口保持同步。

【讨论】:

    【解决方案2】:

    我认为答案与上下文相关,因为它取决于接口的用途以及它们如何适合您的库的架构。

    对象模型

    在我看来,如果您正在创建某种形式的对象模型,您应该将表示对象模型的接口放在程序集中的一个项目中。这样,对接口的引用可以重新分发和编码,而不必担心可能会有所不同的实际实现。它还允许您提供对象模型的初始实现,同时让其他人重新实现它(也许是为了支持新平台或相关软件)。

    一般用途

    如果您打算创建一个类似于 .NET 的 System.Collections.Generic 命名空间中的接口,这些接口将在许多地方重复使用;那么我建议将其放置得足够低,以便多个项目可以访问和实现该接口。但是,这并不意味着您不能在同一个项目中自己实现接口。在这种情况下,这完全取决于您打算在该程序集中做什么。

    其他用途

    另一种用途可能是一些数据库交互系统,其中您有一个定义一些数据库交互器的接口,但您可能有两个或多个实现。例如,您可能有一个专门与 Microsoft Access 数据库交互,一个与 Sql 数据库交互。在这种情况下,在同一个程序集中提供您的接口实现是可行的。

    话虽如此,这完全取决于情况和预期用途。我发现确定它是什么的最佳方法是创建程序集的原型版本并查看您可能需要如何使用它。

    【讨论】:

      【解决方案3】:

      在大多数情况下:视情况而定。

      但在 99% 的情况下,我将接口放入它们自己的程序集中,分组为逻辑单元以防止紧密的接口依赖关系。 在以前的日子里,我只是把它放在第一个实现的地方。这变成了一个紧密耦合的烂摊子,以后不可能分开。

      如果您练习/努力实现松散耦合,我建议将接口移动到单独的程序集。 我更喜欢只包括:

      • 接口,
      • 枚举
      • 常量
      • 接口的扩展方法(不依赖于具体实现)
      • “稳定”类和结构(即永远不会改变或被继承的那些)

      进入“接口程序集”并仅参考:

      • 其他“接口程序集”
      • “工具程序集”(它们本身应该只包含稳定的东西,如扩展方法、常量)

      这不适用于仅在一个程序集中使用的内部使用的接口(这将是 1% 的接口)。

      唯一可以包含在与接口本身相同的程序集中的实现是:

      • 不依赖其他非接口程序集(您不希望包含使用接口程序集的东西,而该程序集只需要用于您不想使用的一种实现)。
      • 是某种默认或无操作实现

      “实现程序集”只能在主程序集中引用,其他程序集只包括接口程序集。这也确保了您不会直接使用该实现或测试该接口是否属于此特殊实现。

      为什么?这样,您的程序集仅依赖于稳定的程序集,而不是紧密耦合的。如果您打算使用依赖注入,这也是首选方式。

      命名空间:

      您应该将实现放在接口的子命名空间中。所以,要拿起你的例子,我建议:

      • 将接口放入MyCompany.AccountPackage.MasterAccounts
      • MyCompany.AccountPackage.MasterAccounts 中加入扩展方法,这个接口的其他稳定的东西
      • 将实现放入正确命名的子命名空间 MyCompany.AccountPackage.MasterAccounts.SQLMasterAccounts 或只是 MyCompany.AccountPackage.MasterAccounts.Implementation

      为什么?

      从实现方面来说,这意味着您无需使用using MyCompany.AccountPackage.MasterAccounts.Interfaces即可获得所有接口和扩展内容。

      从客户端来看,这意味着您将不会在实现程序集中使用过多的智能感知选项(无论如何都不应该包括其他实现程序集),但可以轻松访问主程序集中的实现,其中您选择要使用的具体实现。

      【讨论】:

        【解决方案4】:

        参考以下帖子:

        Proper .NET DLL structure for app

        并且,通常尝试回答以下问题:

        1. 这些接口会被多个程序集使用吗?

        2. 你能减少编号吗?程序集和引用?

        3. 您是否试图将不相关的接口包含到单个程序集中,只是为了减少 dll 数量?

        4. 您考虑过可扩展性和维护吗?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-02
          • 2010-12-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-27
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多