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

时间:2010-08-17 18:07:50

标签: c# ruby interface contract equivalent

我目前正在尝试学习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();
   }
}

6 个答案:

答案 0 :(得分:25)

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

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

答案 1 :(得分:15)

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

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

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

那么,如果两个interface表示不同的东西,具有相同的签名,那么完全interface甚至可以保证你吗?

另一个好例子:

interface

System.Collections.Generic.ICollection<T>.Add接口是什么?

  • 收集的长度不会减少
  • 之前收藏中的所有项目仍然存在
  • interface ICollection<T>: IEnumerable<T>, IEnumerable { void Add(T item); } 在集合

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

这是Add的完全有效的实现:

interface

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

在几乎所有来自Java和.NET的class MyCollection<T>: ICollection<T> { void Add(T item) { Remove(item); } } 的情况下,所有相关的信息实际上都在文档中,而不是在类型中。那么,如果类型不告诉你任何有趣的东西,为什么要保留它们呢?为什么不坚持文档?而这正是Ruby所做的。

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

因此,简而言之:Ruby没有Java sort的等价物。它 但它具有与Java 接口等效的东西,它与Java中的完全相同:文档。

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

特别是在Ruby中,对象的接口取决于它可以做什么,而不是interface是什么,或者是什么{{ 1}}它混入。任何具有class方法的对象都可以附加到。这在单元测试中非常有用,您可以简单地传入module<<而不是更复杂的Array,即使String和{{1}除了他们都有一个名为Logger的方法之外,不要共享一个明确的Array

另一个示例是StringIO,它实现与Logger相同的接口,因此interface接口的很大一部分除了<<之外,没有共享任何共同的祖先。

答案 2 :(得分:5)

接口通常被引入静态类型的OO语言,以弥补多重继承的缺失。换句话说,它们不仅仅是有用的邪恶本身

另一方面,

Ruby:

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

答案 3 :(得分:4)

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

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

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

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

举个例子:

def my_func(options)
  ...
end

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

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