9

我是红宝石的新手。一个简单的例子,我需要什么:

class Animal
   abstract eat()

class Cat < Animal
   eat():
     implementation

class Dog < Animal
   eat():
     implementation

换句话说,所有扩展 Animal 的类都应该需要eat() 方法。

在 JAVA 中我只会使用一个抽象类,但在做了一些研究后我发现很多人不在 Ruby 中使用它,而是推荐使用 mixin / modules。

但是,我不明白,模块是否可以做的不仅仅是包含添加方法。确切地说,模块可以为类设置它们必须实现哪些方法的要求(如果可以,将不胜感激)?

总而言之,在这种情况下,当我想确定所有相同类型的类都有特定的方法并以自己的方式实现它们时,我应该使用什么?

4

5 回答 5

19

使用定义必须实现的方法的模块。

module Animal
  def eat
    raise NotImplementedError
  end
end

class Cat
  include Animal

  def eat
    "Om nom nom"
  end
end

class Dog
  include Animal
end

c = Cat.new
c.eat # => "Om nom nom"

d = Dog.new
d.eat # => NotImplementedError
于 2010-10-23T14:14:40.697 回答
9

Ruby 不提供此功能,不。你有责任确保你的类实现了它们应该实现的东西。

Ruby 无法实现这样的功能的部分原因是 Ruby 类可以重新打开,并且 Ruby 支持在运行时加载任意代码,所以我们无法知道一个类是否实现了某个接口,直到我们尝试调用它。

假设Animal必须有一个eat方法,我执行以下操作:

class Cat < Animal
  def talk
    puts "meow"
  end
end

class Cat
  def eat
    puts "om nom nom"
  end
end

在该文件的末尾,Cat将有它的eat定义,因为 Ruby 类可以多次重新打开和修改。由于eat尚未定义,第一次定义后代码是否会出错?这种实现弊大于利,因为重新开放课程很常见,即使这个例子是人为的。一旦eat方法被调用并且不存在,它是否应该出错,所以我们可以确定它是在我们需要它时定义的?好吧,如果缺少该方法,那无论如何都会发生。解释器永远无法知道另一个类定义是否在进行中,因此在实际调用该方法之前,它永远不会切断您的联系。

简而言之,超类根本不可能要求在 Ruby 中定义方法,因为类的动态特性与这样的目标相矛盾。

对不起!不过,这是一个单元测试可能派上用场的地方,以确保您的子类无论如何都做他们应该做的事情。

于 2010-10-23T14:10:18.030 回答
2

你可以只使用空方法,或者让它们引发错误以强制子类实现它们。

class Base
  def abstract_method
  end

  def mandatory_abstract_method
    raise NotImplementedError.new("You must implement this")
  end
end

不利的一面是,这只会在实际调用该方法时强制执行。Ruby 是一种动态语言,它没有任何编译时检查。

于 2010-10-23T14:08:40.987 回答
1

Ruby 中没有抽象类的等价物。这主要是因为 Ruby 是动态类型的,这意味着抽象类的概念并不真正适用。

于 2010-10-23T14:07:53.747 回答
0

如果你真的想实现抽象,那么你可以使用抽象 gem。

sudo gem install abstraction

引用来自Abstraction gem WIKI的示例示例。

class Car
  abstract

  def go_forward
  # ...
 end
end

Car.new
> AbstractClassError: Car is an abstract class and cannot be instantiated

class Convertible < Car
  def door_count
    2
  end
end

class Sedan < Car
  def door_count
    4
  end
end

Convertible.new  # => #<Convertible:0x8fdf4>
于 2016-05-30T15:03:57.660 回答