如何在ruby中实现抽象类?

如何在ruby中实现抽象类?,ruby,abstract-class,Ruby,Abstract Class,我知道ruby中没有抽象类的概念。但如果真的需要实施的话,该怎么做呢?我尝试了一些像 class A def self.new raise 'Doh! You are trying to write Java in Ruby!' end end class B < A ... ... end A类 def self.new 举起手来!您正在尝试用Ruby编写Java 结束 结束 B类

我知道ruby中没有抽象类的概念。但如果真的需要实施的话,该怎么做呢?我尝试了一些像

class A
  def self.new
    raise 'Doh! You are trying to write Java in Ruby!'
  end
end

class B < A
  ...
  ...
end
A类
def self.new
举起手来!您正在尝试用Ruby编写Java
结束
结束
B类
但是当我尝试实例化B时,它将在内部调用
A.new
,这将引发异常


此外,模块不能实例化,但也不能继承。将新方法私有化也不起作用。有什么指针吗?

我个人提出了抽象类方法中的NotImplementedError。但是,出于您提到的原因,您可能希望将其排除在“new”方法之外。

我不喜欢在Ruby中使用抽象类(几乎总是有更好的方法)。但是,如果您真的认为这是解决这种情况的最佳技术,那么可以使用以下代码片段更明确地说明哪些方法是抽象的:

module Abstract
  def abstract_methods(*args)
    args.each do |name|
      class_eval(<<-END, __FILE__, __LINE__)
        def #{name}(*args)
          raise NotImplementedError.new("You must implement #{name}.")
        end
      END
      # important that this END is capitalized, since it marks the end of <<-END
    end
  end
end

require 'rubygems'
require 'rspec'

describe "abstract methods" do
  before(:each) do
    @klass = Class.new do
      extend Abstract

      abstract_methods :foo, :bar
    end
  end

  it "raises NoMethodError" do
    proc {
      @klass.new.foo
    }.should raise_error(NoMethodError)
  end

  it "can be overridden" do
    subclass = Class.new(@klass) do
      def foo
        :overridden
      end
    end

    subclass.new.foo.should == :overridden
  end
end
模块摘要
def抽象_方法(*args)
args.each do| name|

class_eval(你的方法没有问题。在初始化中引发一个错误似乎很好,当然,只要你的所有子类都覆盖了initialize。但是你不想这样定义self.new。下面是我要做的

class A
  class AbstractClassInstiationError < RuntimeError; end
  def initialize
    raise AbstractClassInstiationError, "Cannot instantiate this class directly, etc..."
  end
end
A类
类AbstractClassInstallionError
另一种方法是将所有这些功能放在一个模块中,正如您所提到的,这是永远无法灌输的。然后将该模块包含在您的类中,而不是从另一个类继承。但是,这会破坏类似super的功能

因此,这取决于您想要如何构造它。虽然模块似乎是解决“如何编写一些专为其他类使用的东西”问题的更干净的解决方案,但请尝试以下方法:

class A
  def initialize
    raise 'Doh! You are trying to instantiate an abstract class!'
  end
end

class B < A
  def initialize
  end
end
A类
def初始化
提出“Doh!您正试图实例化一个抽象类!”
结束
结束
B类
如果要使用不可实例化的类,请在抛出错误之前,在A.new方法中检查self==A


但实际上,模块看起来更像您在这里想要的东西-例如,Enumerable是一种在其他语言中可能是抽象类的东西。从技术上讲,您不能对它们进行子类化,但是调用
include SomeModule
实现了大致相同的目标。这对您不起作用有什么原因吗?

您尝试的目的是什么使用抽象类服务吗?在ruby中可能有更好的方法,但您没有给出任何细节

我的指针是这样的;请使用not继承。

另一个答案:

module Abstract
  def self.append_features(klass)
    # access an object's copy of its class's methods & such
    metaclass = lambda { |obj| class << obj; self ; end }

    metaclass[klass].instance_eval do
      old_new = instance_method(:new)
      undef_method :new

      define_method(:inherited) do |subklass|
        metaclass[subklass].instance_eval do
          define_method(:new, old_new)
        end
      end
    end
  end
end
模块摘要
定义自我附加功能(klass)
#访问对象的类方法副本&例如
元类=lambda{| obj |类#

A.new#raises#在最近6年半的Ruby编程中,我一次也不需要抽象类

如果您认为您需要一个抽象类,那么您在提供/需要抽象类的语言中考虑的太多了,而不是在Ruby中

正如其他人所建议的,MIXIN更适合于那些被认为是接口的东西(如java定义的),并且重新设计你的设计更适合于“需要”C++等其他语言的抽象类。 2019年更新:我已经16年半没有需要Ruby中的抽象类了。所有对我的回答发表评论的人所说的一切都是通过实际学习Ruby和使用适当的工具来解决的,比如模块(甚至给你提供了通用的实现).在我管理的团队中,有人创建了一些基本实现失败的类(比如抽象类),但这些大多是对编码的浪费,因为

NoMethodError
会产生与生产中的
AbstractClassError
完全相同的结果。

a类
class A
  private_class_method :new
end

class B < A
  public_class_method :new
end
私有类方法:新 结束 B类
我想稍后再插话,我认为没有理由阻止某人实例化抽象类

Duck类型语言,如Ruby,在运行时使用方法的存在/不存在或行为来确定是否应该调用它们。因此,当您的问题应用于抽象的方法时,它是有意义的

def get_db_name
   raise 'this method should be overriden and return the db name'
end
这应该是故事的结尾。在Java中使用抽象类的唯一原因是坚持某些方法“填充”,而其他方法的行为在抽象类中。在duck类型语言中,重点是方法,而不是类/类型,因此您应该将您的担忧转移到这一级别


在您的问题中,您基本上是试图从Java中重新创建
abstract
关键字,这是在Ruby中执行Java的代码味道。

我是这样做的,因此它重新定义了new on child类,以找到一个新的on非抽象类。 我仍然看不到在ruby中使用抽象类的任何实用性

puts 'test inheritance'
module Abstract
  def new
    throw 'abstract!'
  end
  def inherited(child)
    @abstract = true
    puts 'inherited'
    non_abstract_parent = self.superclass;
    while non_abstract_parent.instance_eval {@abstract}
      non_abstract_parent = non_abstract_parent.superclass
    end
    puts "Non abstract superclass is #{non_abstract_parent}"
    (class << child;self;end).instance_eval do
      define_method :new, non_abstract_parent.method('new')
      # # Or this can be done in this style:
      # define_method :new do |*args,&block|
        # non_abstract_parent.method('new').unbind.bind(self).call(*args,&block)
      # end
    end
  end
end

class AbstractParent
  extend Abstract
  def initialize
    puts 'parent initializer'
  end
end

class Child < AbstractParent
  def initialize
    puts 'child initializer'
    super
  end
end

# AbstractParent.new
puts Child.new

class AbstractChild < AbstractParent
  extend Abstract
end

class Child2 < AbstractChild

end
puts Child2.new
放置“测试继承”
模块摘要
def新
抛出“摘要!”
结束
def继承(儿童)
@抽象=真
“继承的”
非抽象父类=self.superclass;
而非_abstract_parent.instance_eval{@abstract}
非抽象父类=非抽象父类
结束
放置“非抽象超类为#{Non_abstract_parent}”

(class2行宝石:

你可以试试3个宝石:



我的2倍:我选择了一款简单、轻便的DSL混音器:

module Abstract
  extend ActiveSupport::Concern

  included do

    # Interface for declaratively indicating that one or more methods are to be
    # treated as abstract methods, only to be implemented in child classes.
    #
    # Arguments:
    # - methods (Symbol or Array) list of method names to be treated as
    #   abstract base methods
    #
    def self.abstract_methods(*methods)
      methods.each do |method_name|

        define_method method_name do
          raise NotImplementedError, 'This is an abstract base method. Implement in your subclass.'
        end

      end
    end

  end

end

# Usage:
class AbstractBaseWidget
  include Abstract
  abstract_methods :widgetify
end

class SpecialWidget < AbstractBaseWidget
end

SpecialWidget.new.widgetify # <= raises NotImplementedError
模块摘要
扩展ActiveSupport::关注点
包括做
#接口,用于声明性地指示要创建一个或多个方法
#作为抽象方法处理,仅在子类中实现。
#
#论据:
#-方法(符号或数组)待处理的方法名称列表
#抽象基础
module Abstract
  extend ActiveSupport::Concern

  included do

    # Interface for declaratively indicating that one or more methods are to be
    # treated as abstract methods, only to be implemented in child classes.
    #
    # Arguments:
    # - methods (Symbol or Array) list of method names to be treated as
    #   abstract base methods
    #
    def self.abstract_methods(*methods)
      methods.each do |method_name|

        define_method method_name do
          raise NotImplementedError, 'This is an abstract base method. Implement in your subclass.'
        end

      end
    end

  end

end

# Usage:
class AbstractBaseWidget
  include Abstract
  abstract_methods :widgetify
end

class SpecialWidget < AbstractBaseWidget
end

SpecialWidget.new.widgetify # <= raises NotImplementedError
class Foo
  include AbstractType

  # Declare abstract instance method
  abstract_method :bar

  # Declare abstract singleton method
  abstract_singleton_method :baz
end

Foo.new  # raises NotImplementedError: Foo is an abstract type
Foo.baz  # raises NotImplementedError: Foo.baz is not implemented

# Subclassing to allow instantiation
class Baz < Foo; end

object = Baz.new
object.bar  # raises NotImplementedError: Baz#bar is not implemented
self.abstract_class = true
>> A.new
  (rib):2:in `main'
  (rib):2:in `new'
  (rib):3:in `initialize'
RuntimeError: abstract class
>> B.new
initialized
=> #<B:0x00007f80620d8358>
>>