接口是否与多态性兼容

我遇到了与多态类型(甚至多态接口)交互的接口概念的问题。 我正在开发C#,并希望能够接近这个定义的答案,尽管我认为这仍然为每个人提供了足够的空间来提出答案。

举个例子,假设你想制作一个绘制东西的程序。 您为Paints定义了一个接口,并为绘制的主题定义了一个接口。此外,您还有一些可以更具体的方式绘制的主题。

interface IPainter { void paint(IPaintable paintable); } interface IPaintable { void ApplyBaseLayer(Color c); } interface IDecalPaintable : IPaintable { void ApplyDecal(HatchBrush b); } 

我可以想象制作一个类似于以下的画家:

 class AwesomeDecalPainter : IPainter { public void paint(IPaintable paintable) { IDecalPaintable decalPaintable = (IDecalPaintable)paintable; decalPaintable.ApplyBaseLayer(Color.Red); decalPaintable.ApplyDecal(new HatchBrush(HatchStyle.Plaid, Color.Green)); } } 

当然,如果paintable没有实现IDecalPaintable,这将抛出。 它立即引入了IPainter实现与其操作的IPaintable之间的耦合。 但是我也认为说AwesomeDecalPainter不是IPainter是不合理的,因为它的使用仅限于IPaintable域的一个子集。

所以我的问题实际上是四方面的:

  • 接口是否与多态性兼容?
  • 实现可以在IDecalPaintable上运行的IPainter是一个好的设计吗?
  • 如果它可以专门在IDecalPaintable上运行呢?
  • 是否有任何文献或源代码可以说明接口和多态类型应如何交互?

类的接口意味着该类的“用户”的工具。 接口是该类的公开演示,它应该向任何考虑使用它的人宣传哪些方法和常量可用并可从外部访问。 因此,顾名思义,它始终位于用户和实现它的类之间。

另一方面,抽象类是一种旨在帮助扩展它的类的“实现者”的工具。 它是一个基础架构,可以对具体类应该是什么样子施加限制和指导。 从类设计的角度来看,抽象类在界面上比界面更重要。 在这种情况下,实现者位于抽象类和具体类之间,将后者构建在前者之上。

所以简单地回答你的问题,Interface是尊重代码的“契约”。 当以这种方式使用时,它更适用于多态性的inheritance。

抽象类,它们定义了一个’类型’。 当具体的子类使用抽象类并重新定义方法时,添加新的等等……你会看到多态在行动中。

我知道这篇文章可能会让你更加困惑,在我学习设计模式之前,这对我来说没有意义。 通过一些简单的模式,您将更好地理解每个对象的作用以及inheritance,多态和封装如何共同构建设计简洁的应用程序。

祝好运

接口不仅与多态相兼容 – 它们也是必不可少的。 您似乎缺少的部分想法是,如果有一个像IPaintable这样的接口,期望实现它的每个对象都将提供一些默认的绘制方法,通常封装其他方法,以一些有用的方式配置对象。

例如,IPaintable接口可能定义paint方法:

 void Paint(ICanvas canvas);

请注意,Paint方法没有说明应该绘制什么,也没有说明什么颜色,也没有任何其他内容。 各种可绘制的对象将暴露属性以控制这些事物。 例如,Polygon方法可能会处理OutlineColor和FillColor属性以及SetVertices()方法。 想要绘制大量对象的例程可以接受IEnumerable(Of IPaintable)并简单地在所有对象上调用Paint,而不必知道它们将如何被绘制。 通过调用Paint来绘制对象的事实,除了应该绘制它的canvas之外没有任何参数,决不会阻止Paint方法执行各种奇特的渐变填充,纹理映射,光线跟踪或其他图形效果。 指挥绘画的代码对这些东西一无所知,但是IPaintable对象本身会保存他们需要的所有信息,因此不需要调用代码来提供它。

问题实际上是你定义了一个模糊的界面,合同是一个更合适的术语。 这就像你进入麦当劳并且只是点一个汉堡:

 interface Resturant { Burger BuyBurger(); } 

接受订单的人会在一段时间内看起来有点困惑,但最终他/她会为您提供任何汉堡,因为您没有指定您想要的东西。

这里也是一样的。 你真的只是想定义一些可以涂漆的东西吗? 如果你问我,就像在找麻烦一样。 始终尝试使接口尽可能具体。 拥有几个小型特定接口总比一般大接口更好。

但让我们回到你的例子。 在您的情况下,所有类只需要能够绘制一些东西。 因此我会添加另一个更具体的界面:

  interface IPainter { void Paint(IPaintable paintable); } interface IDecalPainter : IPainter { void Paint(IDecalPaintable paintable); } interface IPaintable { void ApplyBaseLayer(Color c); } interface IDecalPaintable : IPaintable { void ApplyDecal(HatchBrush b); } class AwesomeDecalPainter : IDecalPainter { public void Paint(IPaintable paintable) { IDecalPaintable decalPaintable = paintable as IDecalPaintable; if (decalPaintable != null) Paint(decalPaintable); else paintable.ApplyBaseLayer(Color.Red); } public void Paint(IDecalPaintable paintable) { paintable.ApplyBaseLayer(Color.Red); paintable.ApplyDecal(new HatchBrush(HatchStyle.Plaid, Color.Green)); } } 

我建议您阅读有关SOLID原则的内容。

更新

更健全的接口实现

  interface IPaintingContext { //Should not be object. But my System.Drawing knowledge is limited object DrawingSurface { get; set; } } interface IPaintable { void Draw(IPaintingContext context); } class AwesomeDecal : IPaintable { public void Draw(IPaintingContext paintable) { // draw decal } } class ComplexPaintableObject : IPaintable { public ComplexPaintableObject(IEnumerable paintable) { // add background, border } } 

在这里,您可以创建尽可能复杂的绘画项目。 他们现在知道他们画的是什么,或者在同一表面上使用了什么其他的痛点。

我能正确理解你的问题吗? 我认为你的问题是界面是否可以运用inheritance的基本要素? (即从父接口inheritance的子接口)。

1)如果是这样的话,在语法上肯定,为什么不呢? 2)至于实用性,它可能没什么价值,因为你的子接口基本上没有从你的父接口重用任何东西。