寻找需要多接口继承(不实现)的示例/情况

时间:2012-03-20 16:56:04

标签: c# java interface multiple-inheritance

C#和Java都支持从多个父级继承的接口:

public interface IMyInterface : IInterface1, IInterface2

public interface MyInterface
extends Interface1, Interface2

我一直在查看.NET Framework和JavaAPI文档,以获取使用多个接口继承的示例。

在JavaAPI中,我找到了扩展超接口和一个或多个“标记”接口的子接口的示例(即它们没有定义的方法)。所以“标记”接口并没有真正强制执行任何东西。我可以看到这样做的好处,特别是在引入注释之前。

在.NET中,我发现从已经相关的多个父级继承的接口。例如,IList继承自ICollectionIEnumerable,但ICollection已经是IEnumerable的后代。因此,已经通过单继承实现了IEnumerable对实现的强制执行。

在任何一种情况下,看起来多接口继承都是多余的,或者可以用更好的替代方案替换。

如果没有多接口继承,是否有任何难以或无法实现的示例?

4 个答案:

答案 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。相反,界面将继承ICollectionIEnumerable本身。

视觉示例:

IMine : ICollection<T> != IMine : (ICollection<T>:(IEnumerable<T>:IEnumerable))

相反,它看起来像这样编译:

IMine: ICollection<T>, IEnumerable<T>, IEnumerable

这解释了为什么你得出了你的结论。


关于多接口继承的真实示例,请查看IQueryableIOrderedQueryable示例。这些接口的实际源声明如下:

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子类型AbstractCollectionList

StringBuilder既是CharSequence(读取接口)又是Appendable(写入接口)。我不太喜欢将读写合并在一起 - 就像不可变的值和告诉不要问的接口一样。

显然有(很大程度上是邪恶的)标记接口:SerializableCloneableRandomAccess

GUI代码特别倾向于将回调接口完全不必要地实现到一个bug类中,这通常扩展了它没有理由的类。