接口/抽象类编码标准接口、标准、抽象类

2023-09-03 13:03:23 作者:他夏了夏天丶

我发现了一个建议的C#编码标准,其中指出尽量提供所有抽象类的接口。是否有人知道这个道理呢?

I spotted a proposed C# coding-standard which stated "Try to offer an interface with all abstract classes". Does someone know the rationale for this?

推荐答案

有 .NET框架设计指南一些有趣的东西,说接口和抽象类。

The .NET Framework Design Guidelines have some interesting things to say about interfaces and abstract classes.

在特定的,他们指出,接口具有比类不太灵活的主要缺点,当涉及到一个API的演变。一旦你船的接口,它的成员是永远固定的,任何增加将打破以实现该接口的现有类型的兼容性。然而,航运类提供了更多的灵活性。成员可以在任何时候加入,即使在初始版本已发货,只要它们不是抽象。任何现有的派生类可以继续工作不变。在该框架提供的的System.IO.Stream 抽象类是作为一个例子。它最初出厂时没有进行超时未完成的I / O操作的支持,但2.0版能够添加成员支持这一功能,即使是从现有的子类。

In particular, they note that interfaces have the major drawback of being less flexible than classes when it comes to the evolution of an API. Once you ship an interface, its members are fixed forever, and any additions will break compatibility with the existing types that implement that interface. Whereas, shipping a class offers much more flexibility. Members can be added at any time, even after the initial version has shipped, as long as they are not abstract. Any existing derived classes can continue to work unchanged. The System.IO.Stream abstract class provided in the Framework is given as an example. It initially shipped without support for timing out pending I/O operations, but version 2.0 was able to add members that supported this feature, even from existing subclasses.

因此​​,具有一个对应的接口,用于每个抽象基类提供一些额外的好处。接口不能被公开曝光,或者你的左后卫在广场之一版本的条款。如果你只公开了抽象基类,几乎没有通过在首位的接口获得的。

Thus, having a corresponding interface for each abstract base class provides few additional benefits. The interface cannot be publically exposed, or you're left back at square one in terms of versioning. And if you only expose the abstract base class, there's little gained by having the interface in the first place.

此外,该点往往是有利于他们允许实现分离的合同接口进行。克日什托夫·Cwalina认为,这种说法是似是而非的:它错误地假定你不能单独使用的类实现合同。通过编写驻留在他们的具体实现一个单独的程序抽象类,很容易实现分离的相同的美德。他写道:

Additionally, the point is often made in favor of interfaces that they allow separating contract from implementation. Krzysztof Cwalina argues that this claim is specious: it incorrectly assumes you cannot separate contracts from implementation using classes. By writing abstract classes that reside in a separate assembly from their concrete implementations, it's easy to achieve the same virtues of separation. He writes:

我经常听到有人说接口指定合约。我相信这是一个危险的神话。接口方面,本身并没有指定远远超出使用对象所需的语法。该接口作为合同的神话使人们试图从执行,这是一个伟大的工程实践单独的合同的时候做错误的事情。接口分开语法从实施,这是没有多大用处,而神话提供了做正确的工程的错觉。在现实中,合同的语义,而这些其实是可以pssed一些很好的执行前$ P $。

I often hear people saying that interfaces specify contracts. I believe this is a dangerous myth. Interfaces, by themselves, do not specify much beyond the syntax required to use an object. The interface-as-contract myth causes people to do the wrong thing when trying to separate contracts from implementation, which is a great engineering practice. Interfaces separate syntax from implementation, which is not that useful, and the myth provides a false sense of doing the right engineering. In reality, the contract is semantics, and these can actually be nicely expressed with some implementation.

在一般情况下,提供的方针是 DO青睐定义类通过接口。此外,克日什托夫·评论:

In general, the guideline provided is DO favor defining classes over interfaces. Again, Krzysztof comments:

在三个版本的.NET Framework的过程中,我刚才讲了这个方针与相当多的开发者在我们的队。他们中许多人,包括那些谁最初与准则不同意,说,他们后悔运一些API的接口。我没有听说过,甚至一个案件中,有人感到遗憾的是,他们运一类的。

Over the course of the three versions of the .NET Framework, I have talked about this guideline with quite a few developers on our team. Many of them, including those who initially disagreed with the guideline, have said that they regret having shipped some API as an interface. I have not heard of even one case in which somebody regretted that they shipped a class.

第二个准则认为,一个不要使用抽象类,而不是接口脱钩合同的实施。这里的关键是,正确设计的抽象类仍然允许合同及其履行情况作为接口之间脱钩的程度相同。布赖恩·佩平的个人观点是这样的:

A second guideline argues that one DO use abstract classes instead of interfaces to decouple the contract from implementations. The point here is that correctly-designed abstract classes still allow for the same degree of decoupling between contract and implementation as interfaces. Brian Pepin's personal perspective is thus:

有一件事情我已经开始在做的是烤尽可能多的合同到我的抽象类越好。例如,我可能想有四个重载的方法,其中每个重载提供了一个日益复杂的参数设置。要做到这一点,最好的方法是提供非虚实现对抽象类的这些方法,并有实现的所有路由到一个受保护的抽象方法,提供了实际的实现。通过这样做,你可以写所有的无聊的说法,检查逻辑一次。谁想要实现你的类开发者会感谢你。

Java 抽象类与接口

One thing I've started doing is to actually bake as much contract into my abstract class as possible. For example, I might want to have four overloads to a method where each overload offers an increasingly complex set of parameters. The best way to do this is to provide a nonvirtual implementation of these methods on the abstract class, and have the implementations all route to a protected abstract method that provides the actual implementation. By doing this, you can write all the boring argument-checking logic once. Developers who want to implement your class will thank you.

也许你会做到最好重温经常吹捧的规定,一个派生类表示 IS-A的关系的基类,而一个类实现一个接口有一个 CAN-DO关系与该接口。为了使索赔人应的总是的code输入接口和一个抽象基类,独立于具体的理由这样做,似乎错过了这一点。

Perhaps one would do best by revisiting the oft-touted "rule" that a derived class indicates an IS-A relationship with the base class, whereas a class implementing an interface has a CAN-DO relationship with that interface. To make the claim one should always code both an interface and an abstract base class, independent of specific reasons to do so, seems to miss the point.