Ruby中的抽象方法

问题描述 投票:42回答:6

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

ruby abstract
6个回答
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.

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


15
投票

我喜欢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

现在,如果你创建一个属于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!"

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


7
投票

我喜欢的方法类似但略有不同......我更喜欢它,如下所示,因为它使代码自我记录,给你一些非常类似于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

有些人会抱怨这不太干,并坚持创建一个异常子类和/或将"SubclassResponsibility"字符串放在一个常量,但恕我直言you can dry things up to the point of being chafed, and that is not usually a good thing。例如。如果你的代码库中有多个抽象类,你在哪里定义MESS字符串常量?!?


4
投票

我喜欢使用像abstract_method这样的宝石,它提供了一种dsl rails风格的语法抽象方法:

class AbstractClass
  abstract_method :foo
end

class AbstractModule
  abstract_method :bar
end

class ConcreteClass < AbstractClass
  def foo
    42
  end
end

1
投票

如果未在继承的类中定义方法'foo','bar'和'mate',则此代码将不允许您加载该类。

它没有说明在许多文件中定义的类,但是我们很多人真的在多个文件中定义了类方法吗?我的意思是如果你不计算混合。 (这确实占了上风)

def self.abstract(*methods_array)
  @@must_abstract ||= []
  @@must_abstract = Array(methods_array)
end
def self.inherited(child)
   trace = TracePoint.new(:end) do |tp|
      if tp.self == child #modules also trace end we only care about the class end   
        trace.disable
        missing = ( Array(@@must_abstract) - child.instance_methods(false) )
        raise NotImplementedError, "#{child} must implement the following method(s) #{missing}" if missing.present?
      end
  end 
  trace.enable
end

abstract :foo
abstract :bar, :mate

0
投票

如果要在创建类的实例时抛出错误,可以执行以下操作

class AbstractClass
  def self.new(args)
    instance = allocate # make memory space for a new object
    instance.send(:default_initialize, args)
    instance.send(:initialize, args)
    instance
  end

  #This is called whenever object created, regardless of whether 'initialize' is overridden
  def default_initialize(args)
    self.abstract_method #This will raise error upon object creation
  end
  private :default_initialize

  def initialize(args)
   # This can be overridden by new class
  end
end


class NewClass < AbstractClass
end

NewClass.new #Throw error
© www.soinside.com 2019 - 2024. All rights reserved.