像其他语言一样,Ruby也有接口。
请注意,你必须小心,不要混淆接口的概念,它是一个单位职责、保证和协议的抽象规范,与interface
的概念相混淆。在Java、C#和VB.NET编程语言中,interface
是一个关键字。在Ruby中,我们经常使用前者,但后者根本不存在。
非常重要的是要区分这两个概念。重要的是接口,而不是interface
。 interface
几乎没有任何有用的信息。 Java中的标记接口最好地证明了这一点,这些接口根本没有成员:只需查看java.io.Serializable
和java.lang.Cloneable
; 这两个interface
意味着非常不同的事情,但它们具有完全相同的签名。
因此,如果两个具有不同含义的interface
具有相同的签名,则interface
到底保证了什么?
另一个很好的例子:
interface ICollection<T>: IEnumerable<T>, IEnumerable
{
void Add(T item);
}
什么是System.Collections.Generic.ICollection<T>.Add
的接口?
- 集合的长度不会减少
- 之前在集合中的所有项目仍然存在
item
在集合中
那么这些内容中哪一个实际上出现在interface
中呢?没有!interface
中没有任何内容表明Add
方法必须添加,它也可能从集合中删除元素。
这是该interface
的完全有效实现:
class MyCollection<T>: ICollection<T>
{
void Add(T item)
{
Remove(item);
}
}
另一个例子:在
java.util.Set<E>
中,它实际上在哪里说它是一个集合?没有!或者更准确地说,在文档中。用英语写的。
在几乎所有的 Java 和 .NET 接口中,所有相关信息都在文档中,而不是在类型中。那么,如果这些类型无论如何都不能告诉你任何有趣的东西,为什么还要保留它们呢?为什么不只使用文档呢?这正是 Ruby 所做的。
请注意,在其他一些语言中,“接口”可以以有意义的方式描述。然而,这些语言通常不将描述“接口”的结构称为“interface”,而是称之为“type”。在依赖类型编程语言中,例如,您可以表达“sort”函数返回与原始长度相同的集合、原始集合中的每个元素也在排序后的集合中出现,并且没有更大的元素出现在较小的元素之前等属性。
因此,简而言之:Ruby 没有与 Java 的 “interface” 相当的东西。但它确实有一个与 Java 的 “Interface” 相当的东西,而且它和 Java 中的一样:文档。
此外,就像在 Java 中一样,验收测试也可以用来指定接口。
特别是在 Ruby 中,对象的接口是由它能做什么来确定的,而不是由它是什么类或者混入了什么模块来确定的。任何具有“<<”方法的对象都可以追加。这在单元测试中非常有用,您可以简单地传递一个“Array”或“String”,而不是一个更复杂的“Logger”,即使“Array”和“Logger”除了它们都有一个名为“<<”的方法之外,没有共享明确的接口。
另一个例子是
StringIO
,它实现了与“IO”相同的接口,因此实现了“File”的大部分接口,但除了“Object”之外没有共同的祖先。