【问题标题】:Interfaces separated from the class implementation in separate projects? [closed]接口与单独项目中的类实现分离? [关闭]
【发布时间】:2010-12-10 22:17:12
【问题描述】:

我们从事一个中等规模的项目(3 个开发人员超过 6 个月),需要做出以下决定:我们希望将接口与具体实现分开。第一种是将接口存储在单独的文件中。

我们希望更进一步,进一步分离数据:我们希望在一个 .CS 文件中拥有一个带有接口的项目 (CSPROJ),再加上另一个带有帮助类的 .CS 文件(例如其中使用的一些公共类)这个接口,一些枚举等)。然后,我们想要另一个项目(CSPROJ),它具有工厂模式、具体接口实现和其他“工人”类。

任何想要创建实现此接口的对象的类都必须包括包含接口和公共类的第一个项目,而不是实现本身。

此解决方案有一个很大的缺点:它将程序集的数量乘以 2,因为对于每个“正常”项目,您将拥有一个具有交互的项目和一个具有实现的项目。

你会推荐什么?您认为将所有接口放在一个单独的项目中而不是将一个接口放在自己的项目中是个好主意吗?

【问题讨论】:

  • 所有接口都是public的,我不考虑Remoting、WCF等外部接口。

标签: c# interface


【解决方案1】:

我会区分这样的接口:

  1. 独立接口,您可以在不讨论项目的其余部分的情况下描述其用途。将它们放在一个专用的“接口程序集”中,该程序集可能会被项目中的所有其他程序集引用。典型例子:ILoggerIFileSystemIServiceLocator

  2. 类耦合接口,只有在项目类的上下文中才有意义。将它们放在与它们耦合的类相同的程序集中。

    一个例子:假设你的领域模型有一个Banana 类。如果您通过IBananaRepository 接口检索香蕉,则该接口与香蕉紧密耦合。如果不了解香蕉,就不可能实现或使用接口。因此,接口与Banana 位于同一程序集中是合乎逻辑的。

    前面的例子有一个技术耦合,但这种耦合可能只是一个逻辑上的耦合。例如,IFecesThrowingTarget 接口可能仅作为Monkey 类的协作者才有意义,即使接口声明与Monkey 没有技术链接。

我的回答确实取决于可以将一些耦合到类的概念。将一切隐藏在界面后面是错误的。 Sometimes it's okay to just "new up" a class,而不是通过工厂注入或创建它。

【讨论】:

  • +1 用于解决编程问题;)
  • 有趣的意见!我可能会按照你的建议去做。
  • 将基础设施类型(例如ILoggerIFileSystem 等)移动到与特定于域的类型不同的程序集中绝对是个好主意,但您仍然应该将ILogger 放入与您的具体 Logger 实现相同的程序集,除非有特定原因不这样做(例如,因为其中一个具体实现会发生很大变化,在这种情况下,在单独的程序集中隔离该类可能是有意义的)。
  • 很好的解释,值得出现在心爱的 Head First 的系列中……但是从那以后世界发生了怎样的变化;今天,我相信 IFecesThrowingTarget 在 Monkey 类之外很有意义;)
【解决方案2】:

是的,我认为这是个好主意。实际上,我们一直在这里这样做,最终我们不得不这样做,原因很简单:

我们使用远程处理来访问服务器功能。所以服务器端的Remote Objects需要实现接口,而客户端代码必须能够访问这些接口才能使用远程对象。

一般来说,我认为当你将接口放在一个单独的项目中时,你会更加松散耦合,所以继续做吧。拥有 2 个程序集真的不是问题,不是吗?

补充:

我刚想到:通过将接口放在单独的程序集中,如果其中一些接口足够通用,您还可以获得能够重用接口的好处。

【讨论】:

  • +1 用于提及远程处理。 (编辑以修正错别字)
【解决方案3】:

我认为您应该首先考虑是否所有接口都属于您项目的“公共接口”。

如果它们要由多个项目、可执行文件和/或服务共享,我认为将它们放入单独的程序集中是公平的。

但是,如果它们仅供内部使用并且为了您的方便,您可以选择将它们保存在与实现相同的程序集中,从而使程序集的总量保持相对较低。

【讨论】:

  • 其实我说的只是公共接口。私有的(如果有的话)与实现本身一起包含在项目中。
  • 啊,我明白了。在这种情况下,坚持接受的答案:-)
【解决方案4】:

除非它为您的应用程序架构提供了经证实的好处,否则我不会这样做。

它是good to keep an eye on the number of assemblies you're creating。即使接口及其实现在同一个程序集中,您仍然可以通过一点纪律来实现您正确寻求的解耦。

【讨论】:

  • 我必须同意你的观点,杰夫。事实证明,大量的程序集确实会带来很多问题。
  • 这个链接好像坏了
【解决方案5】:

如果一个接口的实现最终有很多依赖项(对其他程序集等),那么将接口放在一个独立的程序集中可以简单地为更高级别的消费者提供服务。

他们可以引用接口,而不会无意中依赖于特定实现的依赖项。

【讨论】:

    【解决方案6】:

    过去,我们的共享代码中有很多单独的程序集。随着时间的推移,我们发现我们几乎总是分组引用这些内容。这为开发人员增加了工作量,我们不得不寻找类或接口所在的程序集。我们最终根据使用模式组合了其中一些程序集。生活变得更轻松了。

    这里有很多考虑因素 - 您是在为开发人员编写库,您是否将 DLL 部署给异地客户,您是使用远程处理(感谢 Maximilian Mayerl)还是编写 WCF 服务等等。没有一个是正确的答案 - 视情况而定。

    总的来说,我同意 Jeff Sternal 的观点 - 不要分解程序集,除非它提供了经证实的好处。

    【讨论】:

      【解决方案7】:

      这种方法有利也有弊,您还需要根据如何最适合您的架构方法来调整决定。

      在“专业”方面,您可以实现一定程度的分离,以帮助强制执行接口的正确实现。考虑一下,如果您有初级或中级开发人员从事实现工作,接口本身可以在他们只有读取访问权限的项目中定义。也许高层、团队负责人或架构师负责接口的设计和维护。如果在多个项目中使用这些接口,这可以帮助降低仅在一个项目中工作时无意中对其他项目进行重大更改的风险。此外,如果您与向其分发 API 的第三方供应商合作,那么打包接口是一件非常好的事情。

      显然,也有一些不利的一面。该程序集不包含可执行代码。在我工作过的一些商店中,无论出于何种原因,他们都对装配中没有功能感到不满。肯定有额外的开销。根据您设置物理文件和命名空间结构的方式,您可能有多个程序集执行相同的操作(尽管不是必需的)。

      在一个半随机的笔记中,确保很好地记录您的界面。使用 GhostDoc 从接口继承文档是一件美妙的事情。

      【讨论】:

      • 我们没有像仅使用生产代码生成程序集这样严格的规则。我们的主要目的是将程序集与其实现分开。是的,我们试图把它们记录好:)
      • 我很高兴我现在工作的地方也没有这个规则。 ;-)
      【解决方案8】:

      这是一个好主意,我很欣赏接受的答案中的一些区别。由于枚举,尤其是接口本质上都是无依赖的,这赋予了它们特殊的属性,并使它们免受循环依赖甚至只是使系统“脆弱”的复杂依赖图的影响。我的一位同事曾经将一种类似的技术称为“备忘录模式”,并且从未不指出它的有用应用。

      将接口放入已经有许多依赖项的项目中,并且该接口,至少就项目而言,带有产品的所有依赖项。经常这样做,你更有可能面临循环依赖的情况。随之而来的诱惑是用原本不需要的补丁进行补偿。

      就好像将接口与具有许多依赖项的项目耦合在一起会污染它们。接口的设计意图是解耦,因此在大多数情况下,将它们耦合到类几乎没有意义。

      【讨论】:

        猜你喜欢
        • 2021-12-11
        • 2016-06-28
        • 1970-01-01
        • 2014-02-07
        • 2010-12-10
        • 2014-05-11
        • 1970-01-01
        • 2020-07-03
        • 1970-01-01
        相关资源
        最近更新 更多