在Ruby中,C#中的接口相当于什么?

我目前正在尝试学习Ruby,并且我正在尝试更多地了解它在封装和合同方面提供的内容。

在C#中,可以使用接口定义合同。 实现接口的类必须通过为每个定义的方法和属性(以及可能的其他内容)提供实现来满足合同中的条款。 实现接口的单个​​类可以在合同定义的方法范围内执行所需的任何操作,只要它接受相同类型的参数并返回相同类型的结果即可。

有没有办法在Ruby中强制执行此类操作?

谢谢

我在C#中的一个简单例子:

interface IConsole { int MaxControllers {get;} void PlayGame(IGame game); } class Xbox360 : IConsole { public int MaxControllers { get { return 4; } } public void PlayGame(IGame game) { InsertDisc(game); NavigateToMenuItem(); Click(); } } class NES : IConsole { public int MaxControllers { get { return 2; } } public void PlayGame(IGame game) { InsertCartridge(game); TurnOn(); } } 

ruby中没有接口,因为ruby是一种动态类型语言。 接口基本上用于使不同的类可互换,而不会破坏类型安全性。 您的代码可以与每个控制台一起使用,只要它像C#中的控制台一样实现IConsole。 “duck typing”是一个关键字,你可以用它来赶上处理这类问题的动态语言方式。

此外,您可以而且应该编写unit testing来validation代码的行为。 每个对象都有一个respond_to? 您可以在断言中使用的方法。

Ruby拥有接口 ,就像任何其他语言一样。

请注意,您必须注意不要混淆Interface的概念, Interface是一个单元的职责,保证和协议的抽象规范,具有interface的概念,它是Java,C#和VB.NET中的关键字。编程语言。 在Ruby中,我们一直使用前者,但后者根本不存在。

区分这两者非常重要。 重要的是接口 ,而不是interfaceinterface告诉你几乎没什么用处。 没有什么能比Java中的标记接口更好地certificate这一点,它们是完全没有成员的接口:只需看看java.io.Serializablejava.lang.Cloneable ; 这两个interface意味着非常不同的东西,但它们具有完全相同的签名。

那么,如果两个interface意味着不同的东西,具有相同的签名,那么interface 究竟是什么保证了你呢?

另一个好例子:

 interface ICollection: IEnumerable, IEnumerable { void Add(T item); } 

什么是System.Collections.Generic.ICollection.Add接口

  • 集合的长度不会减少
  • 之前收集的所有物品仍然存在
  • item在集合中

哪些实际出现在interface ? 没有! interface中没有任何内容表明Add方法甚至必须添加 ,它也可以从集合中删除一个元素。

这是该interface的完全有效的实现:

 class MyCollection: ICollection { void Add(T item) { Remove(item); } } 

另一个例子:在java.util.Set中,它实际上是说它是一个集合吗? 无处! 或者更准确地说,在文档中。 用英语讲。

几乎所有的interfaces都来自Java和.NET,所有相关信息实际上都在文档中,而不是在类型中。 那么,如果类型不告诉你任何有趣的东西,为什么要保留它们呢? 为什么不坚持文档? 而这正是Ruby所做的。

请注意,还有其他语言可以以有意义的方式实际描述接口 。 但是,这些语言通常不会调用描述接口interface ”的构造,它们称之为type 。 在依赖类型的编程语言中,您可以例如表达sort函数返回与原始集合长度相同的集合的属性,原始中的每个元素也在已排序的集合中,并且不会出现更大的元素在较小的元素之前。

简而言之:Ruby没有Java interface的等价物。 但它确实具有Java 接口的等价物,并且与Java:文档中的完全相同。

此外,就像在Java中一样, Acceptance Tests也可用于指定接口

特别是,在Ruby中,对象的接口由它可以什么决定,而不是它是什么class ,或它混合在哪个module 。任何具有<<方法的对象都可以附加到。 这在unit testing中非常有用,你可以简单地传入一个Array或一个String而不是一个更复杂的Logger ,即使ArrayLogger不共享一个显式interface除了它们都有一个名为<<的方法。

另一个例子是StringIO ,它实现了与IO相同的接口 ,因此实现了File的大部分接口 ,但除了Object之外没有共享任何共同的祖先。

接口通常被引入静态类型的OO语言,以弥补多重inheritance的缺失。 换句话说,它们本身就是一种必要的邪恶,而不是有用的东西。

另一方面,Ruby:

  1. 动态类型语言是“duck typing”,所以如果你想在两个对象上调用方法foo ,它们既不需要inheritance相同的祖先类,也不需要实现相同的接口。
  2. 通过mixins的概念支持多重inheritance,这里也不需要接口。

Ruby并没有真正拥有它们; 接口和契约通常更多地存在于静态世界中,而不是动态。

如果你真的需要,有一个名为Handshake的gem可以实现非正式合同。

Ruby使用模块的概念作为接口的替代(有点)。 Ruby中的设计模式有很多关于两个概念之间差异的非常好的例子,以及为什么ruby选择更灵活的接口替代方案。

http://www.amazon.com/Design-Patterns-Ruby-Russ-Olsen/dp/0321490452

Jorg有一个很好的观点,ruby有接口,而不是关键字。 在阅读一些回复时,我认为这在动态语言中是否定的。 您必须创建unit testing,而不是让编译器捕获方法未实现,而不是通过语言强制执行接口。 它还使理解方法更难以推理,因为当你试图调用它时你必须追捕一个对象是什么。

举个例子:

 def my_func(options) ... end 

如果你看一下这个函数,你就不知道它应该选择哪些选项以及它应该调用哪些方法或属性,而不需要寻找unit testing,调用其他地方,甚至查看方法。 更糟糕的是,该方法甚至可能不使用这些选项,而是将其传递给其他方法。 为什么在编译器捕获时应该编写unit testing。 问题是你必须以不同的方式编写代码来表达动态语言的这种缺点。

虽然有一个好处,那就是动态编程语言可以快速编写一段代码。 我不必编写任何接口声明,后来我可以使用新的方法和参数而无需访问接口来公开它。 权衡是维护的速度。