解决方法
特别是,他们注意到接口的主要缺点是,当涉及到API的发展时,它不如类灵活.一旦发布了接口,其成员将永久修复,并且任何添加都将破坏与实现该接口的现有类型的兼容性.然而,运送课程提供了更大的灵活性.即使在初始版本发布之后,也可以随时添加成员,只要它们不是抽象的.任何现有的派生类都可以继续保持不变. Framework中提供的System.IO.Stream抽象类作为示例给出.它最初发布时不支持超时待处理I / O操作,但2.0版本能够添加支持此功能的成员,甚至可以添加现有的子类.
因此,为每个抽象基类提供相应的接口几乎没有提供额外的好处.界面不能公开曝光,或者你在版本控制方面留在正方形.如果你只公开抽象基类,那么通过首先使用接口几乎没有获得.
此外,关键点通常是支持将接口与实现分开的接口. Krzysztof Cwalina认为这种说法似是而非:它错误地假设你不能将合同与使用类的实现分开.通过编写驻留在单独程序集中的抽象类与其具体实现,可以很容易地实现分离的相同优点.他写:
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.
通常,提供的准则是支持在接口上定义类. Krzysztof再次评论:
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.
第二个准则认为,一个DO使用抽象类而不是接口来将契约与实现分离.这里的要点是正确设计的抽象类仍允许在接口和接口之间实现相同程度的解耦. Brian Pepin的个人观点是:
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关系.为了做出声明,应该始终对接口和抽象基类进行编码,而不考虑这样做的具体原因,似乎忽略了这一点.