Ruby中的抽象方法

Hun*_*len 44 ruby abstract

如何强制子类在Ruby中实现方法.在Ruby中似乎没有一个抽象关键字,这是我在Java中采用的方法.还有另外一种类似Ruby的方法来强制抽象吗?

And*_*ndy 45

在Ruby中,抽象方法被认为不太有用,因为它没有静态类型.

但是,这就是我所做的:

class AbstractThing
  MESS = "SYSTEM ERROR: method missing"

  def method_one; raise MESS; end
  def method_two; raise MESS; end
end

class ConcreteThing < AbstractThing
  def method_one
     puts "hi"
  end
end

a = ConcreteThing.new
a.method_two # -> raises error.
Run Code Online (Sandbox Code Playgroud)

但是,它似乎很少有必要.

  • 如果您只删除`AbstractThing`的全部内容,则会得到完全相同的行为:尝试调用`method_two`时出现异常.事实上,你会得到一个稍微好一些的*行为,因为你得到的是一个`NoMethodError`,而不是一般的非描述性,非语义的`RuntimeError`,它会告诉你你的代码究竟出了什么问题. (8认同)
  • Ruby是强类型的.只是没有静态输入. (7认同)
  • @Jorg.这是大致正确的,当然除了两件事 - 首先,我可以提出任何我喜欢的错误; 我只是简单地保持了这个例子.关键是你得到一个更具体的错误.其次,定义抽象类会让任何读取代码的人都很清楚你的意图(特别是如果你多次将它子类化,通常就是这种情况). (2认同)
  • 这不一样.如果方法是抽象的,那么在加载类时应该会出错,甚至不需要显式调用缺少的方法. (2认同)

Bor*_*cky 16

我喜欢pvandenberk的答案,但我会改进如下:

module Canine      # in Ruby, abstract classes are known as modules
  def bark
    fail NotImplementedError, "A canine class must be able to #bark!"
  end
end
Run Code Online (Sandbox Code Playgroud)

现在,如果你创建一个属于Canine"抽象类"的类(即一个Canine在其祖先中有模块的类),如果发现#bark方法没有实现,它会抱怨:

class Dog
  include Canine   # make dog belong to Canine "abstract class"
end

Dog.new.bark       # complains about #bark not being implemented

class Dog
  def bark; "Bow wow!" end
end

# Now it's OK:
Dog.new.bark #=> "Bow wow!"
Run Code Online (Sandbox Code Playgroud)

请注意,由于Ruby类不是静态的,但总是对更改开放,因此Dog类本身不能强制存在#bark方法,因为它不知道何时应该完成.如果您是程序员,那么您可以在此时对其进行测试.

  • 我正在搜索`NotImplementedError`并遇到[this](http://chrisstump.online/2016/03/23/stop-abusing-notimplementederror/). (2认同)
  • `NotImplementedError` 的目的是表明某个方法在当前平台上不可用(例如,在 Windows 上调用只有基于 nix 的系统才有的 API)。https://ruby-doc.org/core-2.5.0/NotImplementedError.html (2认同)

pva*_*erk 8

我喜欢的方法类似但略有不同......我更喜欢它,如下所示,因为它使代码自我记录,给你一些非常类似于Smalltalk的东西:

class AbstractThing
  def method_one; raise "SubclassResponsibility" ; end
  def method_two; raise "SubclassResponsibility" ; end
  def non_abstract_method; method_one || method_two ; end
end
Run Code Online (Sandbox Code Playgroud)

有些人会抱怨这不太干,并且坚持创建一个异常子类和/或将"SubclassResponsibility"字符串放在一个常数中,但恕我直言,你可以将事情干涸到被擦伤的程度,这通常不是一件好事.例如,如果您的代码库中有多个抽象类,那么您将在哪里定义MESS字符串常量?!?