C# 接口与单独项目中的类实现分离?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1638240/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Interfaces separated from the class implementation in separate projects?
提问by Tomas Walek
We work on a middle-size project (3 developers over more than 6 months) and need to make following decision: We'd like to have interfaces separated from concrete implementation. The first is to store the interface in a separate file.
我们从事一个中等规模的项目(3 个开发人员超过 6 个月),需要做出以下决定:我们希望将接口与具体实现分开。第一种是将接口存储在单独的文件中。
We'd like to go further and separate the data even more: We'd like to have one project (CSPROJ) with interface in one .CS file plus another .CS file with help classes (like some public classes used within this interface, some enums etc.). Then, we'd like to have another project (CSPROJ) with a factory pattern, concrete interface implementation and other "worker" classes.
我们想进一步分离数据:我们希望有一个项目 (CSPROJ) 在一个 .CS 文件中带有接口,另外还有另一个带有帮助类的 .CS 文件(例如在此接口中使用的一些公共类,一些枚举等)。然后,我们想要另一个具有工厂模式、具体接口实现和其他“工人”类的项目(CSPROJ)。
Any class which wants to create an object implementing this interface must include the first project which contains the interfaces and public classes, not the implementation itself.
任何想要创建实现此接口的对象的类都必须包含包含接口和公共类的第一个项目,而不是实现本身。
This solution has one big disadvantage: it multiplies the number of assemblies by 2, because you would have for every "normal" project one project with interace and one with implementation.
这个解决方案有一个很大的缺点:它将程序集的数量乘以 2,因为对于每个“正常”项目,您将拥有一个带有交互的项目和一个带有实现的项目。
What would you recommend? Do you think it's a good idea to place all interfaces in one separate project rather than one interface in its own project?
你会推荐什么?您认为将所有接口放在一个单独的项目中而不是将一个接口放在自己的项目中是个好主意吗?
采纳答案by Wim Coenen
I would distinguish between interfaces like this:
我会区分这样的接口:
Standalone interfaceswhose purpose you can describe without talking about the rest of your project. Put these in a single dedicated "interface assembly", which is probably referenced by all other assemblies in your project. Typical examples:
ILogger
,IFileSystem
,IServiceLocator
.Class coupled interfaceswhich really only make sense in the context of your project's classes. Put these in the same assembly as the classes they are coupled to.
An example: suppose your domain model has a
Banana
class. If you retrieve bananas through aIBananaRepository
interface, then that interface is tightly coupled to bananas. It is impossible to implement or use the interface without knowing something about bananas. Therefore it is only logical that the interface resides in the same assembly asBanana
.The previous example has a technical coupling, but the coupling might just be a logical one. For example, a
IFecesThrowingTarget
interface may only make sense as a collaborator of theMonkey
class even if the interface declaration has no technical link toMonkey
.
独立接口,您可以在不谈论项目的其余部分的情况下描述其目的。将它们放在一个专用的“接口程序集”中,该程序集可能会被项目中的所有其他程序集引用。典型例子:
ILogger
,IFileSystem
,IServiceLocator
。类耦合接口实际上只在项目类的上下文中有意义。将它们放在与它们耦合的类相同的程序集中。
一个例子:假设你的领域模型有一个
Banana
类。如果您通过IBananaRepository
接口检索香蕉,那么该接口与香蕉紧密耦合。如果不了解香蕉,就不可能实现或使用该接口。因此,接口与Banana
.前面的示例具有技术耦合,但耦合可能只是逻辑耦合。例如,一个
IFecesThrowingTarget
接口只能是有意义的的合作者Monkey
类,即使接口声明没有技术链接Monkey
。
My answer does depend on the notion that it's okay to have somecoupling to classes. Hiding everythingbehind an interface would be a mistake. Sometimes it's okay to just "new up" a class, instead of injecting it or creating it via a factory.
我的答案确实取决于这样一种观念,即与类有一些耦合是可以的。将所有内容隐藏在界面后面将是一个错误。有时可以“新建”一个类,而不是注入它或通过工厂创建它。
回答by Maximilian Mayerl
Yes, I think this is a good idea. Actually, we do it here all the time, and we eventually have to do it because of a simple reason:
是的,我认为这是个好主意。其实我们一直在这里做,最终不得不做,原因很简单:
We use Remoting to access server functionality. So the Remote Objects on the server need to implement the interfaces and the client code has to have access to the interfaces to use the remote objects.
我们使用远程处理来访问服务器功能。因此服务器上的远程对象需要实现接口,客户端代码必须能够访问接口才能使用远程对象。
In general, I think you are more loosely coupled when you put the interfaces in a separate project, so just go along and do it. It isn't really a problem to have 2 assemblies, is it?
一般来说,我认为当你把接口放在一个单独的项目中时,你的耦合会更加松散,所以就去做吧。有 2 个程序集并不是真正的问题,是吗?
ADDITION:
添加:
Just crossed my mind: By putting the interfaces in a separate assembly, you additionally get the benefit of being able to reuse the interfaces if a few of them are general enough.
我突然想到:通过将接口放在单独的程序集中,如果其中一些接口足够通用,您还可以获得能够重用接口的好处。
回答by Jeff Sternal
I wouldn't do it unless it offers a proven benefit for your application's architecture.
除非它为您的应用程序架构提供了经过验证的好处,否则我不会这样做。
It's good to keep an eye on the number of assemblies you're creating. Even if an interface and its implementation are in the same assembly, you can still achieve the decoupling you rightly seek with a little discipline.
这是很好的照看组件您创建的数量。即使一个接口和它的实现在同一个程序集中,你仍然可以通过一些纪律来实现你正确寻求的解耦。
回答by Rob van Groenewoud
I think it you should consider first whether ALL interfaces belong to the 'public interface' of your project.
我认为您应该首先考虑所有接口是否属于您项目的“公共接口”。
If they are to be shared by multiple projects, executables and/or services, i think it's fair to put them into a separate assembly.
如果它们要由多个项目、可执行文件和/或服务共享,我认为将它们放入单独的程序集中是公平的。
However, if they are for internal use only and there for your convenience, you could choose to keep them in the same assembly as the implementation, thus keeping the overall amount of assemblies relatively low.
但是,如果它们仅供内部使用并且为了您的方便,您可以选择将它们与实现保存在同一个程序集中,从而使程序集的总量保持在相对较低的水平。
回答by Joseph Ferris
There are pros and cons to the approach, and you will also need to temper the decision with how it best fits into your architectural approach.
这种方法有利有弊,您还需要根据它如何最适合您的架构方法来调整决策。
On the "pro" side, you can achieve a level of separation to help enforce correct implementations of the interfaces. Consider that if you have junior- or mid-level developer working on implementations, the interfaces themselves can be defined in a project that they only have read access on. Perhaps a senior-level, team lead, or architect is responsible for the design and maintenance of the interfaces. If these interfaces are used on multiple projects, this can help mitigate the risk of unintentional breaking changes on other projects when only working in one. Also, if you work with third party vendors who you distribute an API to, packaging the interfaces is a very good thing to do.
在“专业”方面,您可以实现一定程度的分离,以帮助强制执行接口的正确实现。考虑到如果您有从事实现的初级或中级开发人员,接口本身可以在他们只有读访问权限的项目中定义。也许高级、团队负责人或架构师负责接口的设计和维护。如果这些接口用于多个项目,这有助于降低仅在一个项目中工作时无意中破坏其他项目更改的风险。此外,如果您与向其分发 API 的第三方供应商合作,则打包接口是一件非常好的事情。
Obviously, there are some down sides. The assembly does not contain executable code. In some shops that I have worked at, they have frowned upon not having functionality in an assembly, regardless of the reason. There definitely is additional overhead. Depending on how you set up your physical file and namespace structure, you might have multiple assemblies doing the same thing (although not required).
显然,也有一些不利的方面。该程序集不包含可执行代码。在我工作过的一些商店中,无论出于何种原因,他们都不赞成装配中没有功能。肯定有额外的开销。根据您设置物理文件和命名空间结构的方式,您可能有多个程序集做同样的事情(尽管不是必需的)。
On a semi-random note, make sure to document your interfaces well. Documentation inheritance from interfaces using GhostDoc is a beautiful thing.
在半随机的笔记中,确保很好地记录您的界面。使用 GhostDoc 从接口继承文档是一件美妙的事情。
回答by TrueWill
We used to have quite a number of separate assemblies in our shared code. Over time, we found that we almost invariably referenced these in groups. This made more work for the developers, and we had to hunt to find what assembly a class or interface was in. We ended up combining some of these assemblies based on usage patterns. Life got easier.
我们曾经在我们的共享代码中有相当多的独立程序集。随着时间的推移,我们发现我们几乎总是成群结队地引用这些内容。这给开发人员带来了更多的工作,我们不得不寻找类或接口所在的程序集。我们最终根据使用模式组合了其中的一些程序集。生活变得轻松了。
There are a lot of considerations here - are you writing a library for developers, are you deploying the DLLs to offsite customers, are you using remoting (thanks, Maximilian Mayerl) or writing WCF services, etc. There is no one right answer - it depends.
这里有很多考虑因素 - 您是否为开发人员编写了一个库,您是否将 DLL 部署到异地客户,您是使用远程处理(感谢,Maximilian Mayerl)还是编写 WCF 服务等。没有一个正确的答案 - 它要看。
In general I agree with Jeff Sternal - don't break up the assemblies unless it offers a proven benefit.
总的来说,我同意 Jeff Sternal 的观点——不要拆散程序集,除非它提供了经证实的好处。
回答by matt
If an implementation of an interface ends up having a lot of dependencies (on other assemblies, etc), then having the interface in an isolated assembly can simply life for higher level consumers.
如果接口的实现最终具有很多依赖关系(对其他程序集等),那么将接口放在隔离的程序集中可以简单地为更高级别的使用者服务。
They can reference the interface without inadvertently becoming dependent on the specific implementation's dependencies.
它们可以引用接口,而不会无意中变得依赖于特定实现的依赖项。
回答by Pat Pattillo
This is a good idea and I appreciate some of the distinctions in the accepted answer. Since both enumerations and especially interfaces are by their very nature dependency-less this gives them special properties and makes them immune from circular dependencies and even just complex dependency graphs that make a system "brittle". A co-worker of mine once called a similar technique the "memento pattern" and never failed to point out a useful application of it.
这是一个好主意,我很欣赏接受的答案中的一些区别。由于枚举和特别是接口本质上都是无依赖的,这赋予了它们特殊的属性,并使它们免受循环依赖的影响,甚至只是使系统“脆弱”的复杂依赖图。我的一位同事曾将类似的技术称为“纪念品模式”,并且从未没有指出它的有用应用。
Put an interface into a project that already has many dependencies and that interface, at least with respect to the project, comes with all the dependencies of the product. Do this often and you're more likely to face situations with circular dependencies. The temptation is then to compensate with patches that wouldn't otherwise be needed.
将接口放入已经有很多依赖项的项目中,并且该接口,至少对于项目而言,带有产品的所有依赖项。经常这样做,你更有可能面临循环依赖的情况。然后诱惑是用原本不需要的补丁来补偿。
It's as if coupling interfaces with projects having many dependencies contaminates them. The design intent of interfaces is to de-couple so in most cases it makes little sense to couple them to classes.
就好像将接口与具有许多依赖项的项目耦合在一起会污染它们。接口的设计意图是解耦,因此在大多数情况下,将它们与类耦合是没有意义的。