我们从事中型项目(超过6个月的3位开发人员)并需要做出以下决定:我们希望将接口与具体实现分开。第一种是将接口存储在单独的文件中。
我们希望进一步将数据分开:我们希望在一个.CS文件中添加一个带有接口的项目(CSPROJ)以及带有帮助类的另一个.CS文件(就像在其中使用的一些公共类)这个界面,一些枚举等)。然后,我们想要另一个项目(CSPROJ),它具有工厂模式,具体的接口实现和其他“工作者”类。
任何想要创建实现此接口的对象的类都必须包含第一个包含接口和公共类的项目,而不是实现本身。
这个解决方案有一个很大的缺点:它将程序集的数量乘以2,因为每个“普通”项目都有一个带有interace的项目和一个带有实现的项目。
你会推荐什么?您认为将所有接口放在一个单独的项目中而不是在自己的项目中的一个接口上是一个好主意吗?
答案 0 :(得分:65)
我会区分这样的接口:
独立界面您可以在不谈论项目其余部分的情况下描述其目的。将它们放在一个专用的“接口组件”中,它可能被项目中的所有其他组件引用。典型示例:ILogger
,IFileSystem
,IServiceLocator
。
类耦合接口,这在项目的类上下文中才有意义。将它们放在与它们所连接的类相同的程序集中。
示例:假设您的域模型具有Banana
类。如果您通过IBananaRepository
界面检索香蕉,那么该界面与香蕉紧密相连。在不了解香蕉的情况下实现或使用界面是不可能的。因此,接口与Banana
位于同一程序集中是合乎逻辑的。
前面的例子有一个技术耦合,但耦合可能只是一个逻辑耦合。例如,IFecesThrowingTarget
接口可能仅作为Monkey
类的协作者才有意义,即使接口声明没有到Monkey
的技术链接。
我的回答确实取决于可以将某些耦合到类的概念。隐藏界面背后的一切将是一个错误。 Sometimes it's okay to just "new up" a class,而不是通过工厂注入或创建它。
答案 1 :(得分:12)
是的,我认为这是一个好主意。实际上,我们一直在这里做,最后我们必须这样做,原因很简单:
我们使用Remoting来访问服务器功能。因此服务器上的远程对象需要实现接口,客户端代码必须能够访问接口才能使用远程对象。
一般情况下,当您将接口放在一个单独的项目中时,我认为您更松散耦合,所以只需继续执行即可。拥有2个组件并不是一个真正的问题,是吗?
此外:
刚刚想到:通过将接口放在一个单独的程序集中,您还可以获得能够重用接口的好处,如果其中一些接口足够通用的话。
答案 2 :(得分:8)
除非它为您的应用程序架构提供经证实的好处,否则我不会这样做。
这是good to keep an eye on the number of assemblies you're creating。即使一个接口及其实现在同一个程序集中,你仍然可以通过一点点的训练来实现正确寻求的解耦。
答案 3 :(得分:7)
我认为您首先应该考虑所有接口是否属于项目的“公共接口”。
如果要由多个项目,可执行文件和/或服务共享它们,我认为将它们放入单独的程序集中是公平的。
但是,如果它们仅供内部使用并且为方便起见,您可以选择将它们保存在与实现相同的程序集中,从而使组件的总量相对较低。
答案 4 :(得分:5)
如果接口的实现最终具有很多依赖性(在其他程序集上等),那么将接口置于隔离的程序集中对于更高级别的消费者来说可以简单地生活。
他们可以引用该接口,而不会无意中依赖于特定实现的依赖性。
答案 5 :(得分:3)
我们曾经在共享代码中拥有相当多的独立程序集。随着时间的推移,我们发现我们几乎总是在小组中引用它们。这为开发人员提供了更多的工作,我们不得不寻找一个类或接口所在的程序集。我们最终根据使用模式组合了一些这些程序集。生活变得更轻松。
这里有很多注意事项 - 你是在为开发人员编写一个库,是将DLL部署到异地客户,是使用远程处理(感谢Maximilian Mayerl)还是编写WCF服务等等。没有人权利答案 - 这取决于。
总的来说,我同意Jeff Sternal的意见 - 除非它提供了可靠的好处,否则不要拆开组件。
答案 6 :(得分:2)
这种方法有利有弊,你还需要根据它最适合你的架构方法来决定这个决定。
在“专业”方面,您可以实现一定程度的分离,以帮助实施正确的接口实现。考虑一下,如果您有初级或中级开发人员从事实现,那么接口本身可以在他们只有读访问权的项目中定义。也许高级,团队负责人或架构师负责接口的设计和维护。如果在多个项目中使用这些接口,这可以帮助减少仅在其中一个项目中工作时无意中断更改的风险。此外,如果您与分发API的第三方供应商合作,打包接口是一件非常好的事情。
显然,有一些不利因素。程序集不包含可执行代码。在我工作过的一些商店里,无论原因如何,他们都不赞成在装配中没有功能。肯定会有额外的开销。根据您设置物理文件和命名空间结构的方式,您可能有多个程序集执行相同的操作(尽管不是必需的)。在半随机说明中,请务必妥善记录您的界面。使用GhostDoc从接口继承文档是一件很美妙的事情。
答案 7 :(得分:0)
这是一个好主意,我很欣赏接受的答案中的一些区别。由于枚举和特别是接口本身都是依赖性的,因此它们赋予它们特殊的属性并使它们免受循环依赖性的影响,甚至只是复杂的依赖图,这使得系统变得脆弱"。我的一位同事曾经把类似的技术称为" memento模式"并且从未指出它的有用应用。
将接口放入已经具有许多依赖项的项目中,并且该接口(至少就项目而言)附带产品的所有依赖项。经常这样做,你更有可能面对循环依赖的情况。然后,诱惑就是补偿那些本来不需要的补丁。
好像与具有许多依赖关系的项目的耦合接口会污染它们。接口的设计意图是解耦,因此在大多数情况下将它们耦合到类是没有意义的。