Ruby中抽象类的替代方案?

时间:2010-10-23 14:01:12

标签: ruby abstract-class mixins

我是Ruby新手。一个简单的例子,我需要的是:

class Animal
   abstract eat()

class Cat < Animal
   eat():
     implementation

class Dog < Animal
   eat():
     implementation

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

在JAVA中,我只使用一个抽象类,但经过一些研究后我发现很多人不会在Ruby中使用它,而建议使用mixin / modules。

但是,我不明白,如果模块可以做的不仅仅是包含一个附加方法。确切地说,模块是否可以为类设置它们必须实现的方法(如果是,可以赞赏一个例子)?

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

5 个答案:

答案 0 :(得分: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

答案 1 :(得分: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中定义一个方法,因为类的动态性质与这样的目标相矛盾。

抱歉!不过,这是一个单元测试可能会派上用场的地方,以确保您的子类能够完成他们应该做的事情。

答案 2 :(得分:2)

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

class Base
  def abstract_method
  end

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

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

答案 3 :(得分:1)

Ruby中没有与抽象类相同的东西。这主要是因为Ruby是动态类型的,这意味着抽象类的概念并不真正适用。

答案 4 :(得分: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>