C#和Java都支持从多个父级继承的接口:
public interface IMyInterface : IInterface1, IInterface2
public interface MyInterface
extends Interface1, Interface2
我一直在查看.NET Framework和JavaAPI文档,以获取使用多个接口继承的示例。
在JavaAPI中,我找到了扩展超接口和一个或多个“标记”接口的子接口的示例(即它们没有定义的方法)。所以“标记”接口并没有真正强制执行任何东西。我可以看到这样做的好处,特别是在引入注释之前。
在.NET中,我发现从已经相关的多个父级继承的接口。例如,IList
继承自ICollection
和IEnumerable
,但ICollection
已经是IEnumerable
的后代。因此,已经通过单继承实现了IEnumerable
对实现的强制执行。
在任何一种情况下,看起来多接口继承都是多余的,或者可以用更好的替代方案替换。
如果没有多接口继承,是否有任何难以或无法实现的示例?
答案 0 :(得分:1)
您应该查看the Interface Segregation Principle (ISP)中的SOLID principles。基本上,您应该创建插入在一起的小接口,而不是试图寻找组合它们的方法。为什么有些方法对某些类没用?这通常是多重继承的原因。
至于设计是否不可能,我会说不,因为你可以创建一个巨大的界面。然而,ISP指出这种方法的否定性,将使维护成为潜在的困难,但是从初始设计开始,我会说不,你不需要多重继承来完成实现。它可能看起来很混乱
答案 1 :(得分:1)
如果您希望实现界面的所有对象都是 IDisposable 和 IComparable 。
例如,如果您有一组资源,您可能希望根据它们的某些属性对它们进行排序或过滤(使用IEquatable)。这意味着所有对象都必须实现这两个接口,您可以使用通用接口来强制执行此
IResource<T>: IDisposable, IComparable<T>, IEquatable<T>
答案 2 :(得分:1)
如果我理解你描述.NET接口继承链的方式,那么你就错了。这是一个容易犯的错误,因为文档使它看起来那样。 IList<T>
仅显式继承自ICollection<T>
;它不继承自ICollection<T>
,IEnumerable<T>
和IEnumerable
。以下是参考来源的实际定义:
public interface IList<T> : ICollection<T>
同样适用于ICollection<T>
,它只会继承自IEnumerable<T>
。在编译期间,继承树在某种意义上是对接口进行展平和重复数据删除。因此,继承ICollection
的接口不仅继承该接口,而接口继承IEnumerable
。相反,界面将继承ICollection
和IEnumerable
本身。
视觉示例:
IMine : ICollection<T> != IMine : (ICollection<T>:(IEnumerable<T>:IEnumerable))
相反,它看起来像这样编译:
IMine: ICollection<T>, IEnumerable<T>, IEnumerable
这解释了为什么你得出了你的结论。
关于多接口继承的真实示例,请查看IQueryable
和IOrderedQueryable
示例。这些接口的实际源声明如下:
public interface IQueryable<out T> : IEnumerable<T>, IQueryable {}
public interface IOrderedQueryable<out T> : IQueryable<T>, IOrderedQueryable {}
IQueryable
需要有一个合同,指明您可以迭代每个元素,但也能够区分简单IEnumerable
,而不是全部IEnumerable
类型可以在IQueryProvider
和静态Queryable
类中使用。
另一个有趣的是System.Collections.Concurrent
命名空间。
public interface IProducerConsumerCollection<T> : IEnumerable<T>, ICollection
这很有趣,因为它继承自ICollection
(非通用)和IEnumerable<T>
,它们都继承自IEnumerable
。当然,这不是问题,但这是另一个很好的例子。如果IProducerConsumerCollection<T>
继承自ICollection<T>
而非其非泛型对应,我确信它不会明确继承自IEnumerable<T>
。它具有ICollection
中定义的大小,(旧)枚举器和同步方法行为,然后还有IEnumerable<T>
中定义的通用枚举行为
有两个例子。我发现了更多,但我认为这些已经足够了。
答案 3 :(得分:0)
在Java中:
Comparable
通常是您想要与主要类型分开的内容。
AbstractList
子类型AbstractCollection
和List
。
StringBuilder
既是CharSequence
(读取接口)又是Appendable
(写入接口)。我不太喜欢将读写合并在一起 - 就像不可变的值和告诉不要问的接口一样。
显然有(很大程度上是邪恶的)标记接口:Serializable
,Cloneable
和RandomAccess
。
GUI代码特别倾向于将回调接口完全不必要地实现到一个bug类中,这通常扩展了它没有理由的类。