在高层次上,我对Interfaces的了解如下:
对我而言,这立即暴露了两个主要问题:
因为任何实现类都必须实现其所有方法,这实际上意味着一旦使用了接口就无法更改。在Interface中添加或删除方法意味着改变使用它的每个类。答案可能正是如此;他们应该从不更改,但我们怎样才能保证我们的设计稳定?
假设实现接口的类实际上在其实现中使用相同的逻辑。这是代码重复,使其难以维护。这不是基类和继承的重点吗?
我接受了这种想法,因为我认为我已经很好地掌握了它。我认为接口是类的'插入'或'插入',给它一些额外的功能,其功能不依赖于那种类型,例如接口可能定义计算表面积的方法,但是很多东西都有一个表面区域,而不仅仅是“形状”或“建筑”,所以创建一个'螺栓'(接口)来计算表面积似乎是合理的,但是该接口的每个实现都可能是同样,那么收益在哪里?这是一个公平的评论吗?我相信他们提供了很大的好处,我还没有看到它。
答案 0 :(得分:1)
关于第一个问题 - 接口是为系统提供松散耦合的方法。可能有帮助的一个例子是HTTP协议。它是一个允许设备相互通信的接口 - 但这些设备有时没有任何共同之处。您可能拥有PC,笔记本电脑,平板电脑,智能手机,智能电视,各种运行桌面Windows,Linux,Mac,任何移动操作系统,嵌入式操作系统等的设备。尽管它们完全不同,但它们共享一个界面,并且可以轻松地相互通信。
另一个例子 - 迭代器模式。您当然使用了多个数据结构,并且已经提升了枚举它们的冲动。迭代器是一个接口,允许您在数组,链表,队列,堆栈上使用相同的代码。因此,如果您因任何原因需要更改您的收藏,您可以在不破坏世界另一端的项目的情况下这样做。请注意,我刚刚提到的集合以不同的方式实现,并且不共享任何代码。
关于第二个问题 - 如果您的类确实以相同的方式实现了单个接口,那么您就没有理由不使用实现该接口的基类。例如,考虑从.NET中选择的以下层次结构:
interface IEnumerable
class Collection : IEnumerable
class ObservableCollection: Collection
class MailAddressCollection: Collection
class KeyedCollection: Collection
... about 40 other children of Collection
(为清楚起见省略了一些细节)
正如您所看到的,需要相同的接口实现的派生类是从一个基类派生而不是直接从接口派生的,因此不会重复代码。
答案 1 :(得分:1)
至于你的第一个问题,它很有道理。如果类实现接口并且接口发生更改,则必须编辑所有接口。否则,它们不会保持对接口的忠诚,这意味着依赖于它们实现接口的类会中断。
接口是契约,实现它们的类承诺实现某些功能的其他类。如果他们不这样做,那么首先拥有界面的重点就会丢失。
答案 2 :(得分:1)
在其他答案中,重要的是要注意接口通常应该封装尽可能少的逻辑来执行相关操作。一个非常简单的例子:
public IVehicle
{
void Start();
void Stop();
void Accelerate();
void Decelerate();
void TurnLeft();
void TurnRight();
void Reverse();
}
public interface IAeronauticVehicle : IVehicle
{
void TakeOff();
void Land();
void Ascend();
void Descend();
}
然后你可以
public class Car : IVehicle
{
// ... implementation ...
}
public class Airplane : IAeronauticVehicle
{
// ... similar IVehicle implementation
// ... and then the IAeronauticVehicle implementation
// You could even nullify certain IVehicle methods that don't apply:
public void Reverse()
{
throw new NotSupportedException();
}
}
这是一个非常人为的例子,但它说明您的IVehicle接口不需要关注可能仅适用于IAeronauticVehicle实现的扩展属性或方法。您可以稍后添加。通过这样做,您可以扩展Airplane类的功能和使用IAeronauticVehicle的任何代码,而无需更改IVehicle定义的基本契约
这是一个典型的例子是IEnumerable接口,它只定义了一个方法GetEnumerator
。任何类,无论目的如何,如果要返回一组可枚举的项,都可以实现此接口。这样,这个类立即在IEnumerable支持的任何地方变得可用。使用您的IEnumerable实现的代码不关心您的类上的任何其他方法,例如FetchRecordsFromDatabase()
或ValidateInput()
或您的类定义的任何其他方法。
界面不应该是无所不包的,因此必须(几乎)不得出现必须更改界面的问题。
答案 3 :(得分:0)
有多个实现单个接口的类为您提供了一种使用单个方法从这些不同类操作实例化对象的好方法。只需通过声明具有所实现界面的那些。而不是为每个类编写不同的方法。这是我带头的第一个好处;)