当前位置:  开发笔记 > 编程语言 > 正文

如何在ruby中实现抽象类?

如何解决《如何在ruby中实现抽象类?》经验,为你挑选了8个好方法。

我知道ruby中没有抽象类的概念.但是,如果它需要实施,那该怎么办呢?我试过像......

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

class B < A
  ...
  ...
end

但是当我尝试实例化B时,它会在内部调用A.new哪个会引发异常.

此外,模块无法实例化,但也无法继承.使新方法私有也行不通.有什么指针吗?



1> Dan Rosensta..:

只是为了在这里编写,我认为没有理由阻止某人实例化抽象类,特别是因为他们可以动态添加方法.

鸭子类型语言(如Ruby)在运行时使用方法的存在/不存在或行为来确定是否应该调用它们.因此,您的问题,因为它适用于抽象方法,是有道理的

def get_db_name
   raise 'this method should be overriden and return the db name'
end

这应该是关于故事的结尾.在Java中使用抽象类的唯一原因是坚持某些方法被"填充",而其他方法则在抽象类中使用它们的行为.在鸭子打字语言中,重点是方法,而不是类/类型,所以你应该把你的担忧转移到那个级别.

在你的问题中,你基本上是在尝试abstract从Java 重新创建关键字,这是在Ruby中编写Java的代码味道.


抱歉,"赞成过继承"不会说"总是用户构成".虽然通常应该避免继承,但是当它们更适合时,有几个用例.不要盲目追随这本书.
@ChristopherPerry我仍然没有得到它.如果父和兄弟*毕竟是*相关的,我为什么不想要这种依赖呢?我希望这种关系是明确的?另外,要在其他类中组合某个类的对象,您还需要知道它的定义.继承通常作为组合实现,它只是使组合对象的接口成为嵌入它的类的接口的一部分.因此,您需要定义嵌入或继承的对象.或者也许你在谈论其他事情?你能详细说明一下吗?
即使在Java中,抽象类也是代码气味.
@Christopher Perry:有什么原因吗?
@SasQ,你不需要知道父类的实现细节来组成它,你只需要知道它的'API.但是,如果你继承你,则依赖于父母的实施.如果实现更改,您的代码可能会以意想不到的方式中断 更多详情[此处](http://books.google.com/books?id=ka2VUBqHiWkC&pg=PA81&lpg=PA81&dq=inheritance+vs+composition+joshua+bloch&source=bl&ots=yYJnKhr5R3&sig=Q6EbGV0EZXh8Ugv26Z69tGT9N0I&hl=zh-CN&sa=X&ei=6TEmUpvUKvipsASLvoGIBA&ved=0CCwQ6AEwAA# v =&onepage q =继承%20VS%20composition%20joshua%20bloch&F =假)

2> nakajima..:

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

基本上,您只需abstract_methods使用抽象方法列表调用,当它们被抽象类的实例调用时,NotImplementedError将引发异常.


这听起来并不是"NotImplementedError"的有效用例,它本质上意味着"依赖于平台,不适用于您的".[见文档](http://ruby-doc.org/core-1.9.3/NotImplementedError.html).
您正在使用元编程替换单行方法,现在需要包含mixin并调用方法.我认为这根本不是说明性的.

3> Andrew Peter..:

试试这个:

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

class B < A
  def initialize
  end
end


如果你想在B的'#initialize`中使用super,你实际上可以在A#initialize`中提出任何东西,如果self.class == A`.

4> bluehavana..:
class A
  private_class_method :new
end

class B < A
  public_class_method :new
end


另外,可以使用父类的继承钩子使构造方法在所有子类中自动可见:def A.inherited(subclass); subclass.instance_eval {public_class_method:new}; 结束

5> 小智..:

我的2¢:我​​选择简单轻巧的DSL mixin:

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

当然,在这种情况下,为初始化基类添加另一个错误将是微不足道的.



6> Fred Willmor..:

对于rails世界中的任何人来说,在模型文件中使用此声明来实现ActiveRecord模型作为抽象类:

self.abstract_class = true



7> Austin Ziegl..:

在编程Ruby的最后6年半里,我不需要一次抽象类.

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

正如其他人所建议的那样,mixin更适合于那些应该是接口的东西(正如Java定义的那样),重新思考你的设计更适合那些需要来自其他语言(如C++)的抽象类的东西.

更新2019:在使用16年半的时间里,我不需要Ruby中的抽象类.通过实际学习Ruby并使用适当的工具(如模块(甚至可以为您提供常见实现)),可以解决所有人对我的回复所做的评论.我管理的团队中有些人创建了基本实现失败的类(如抽象类),但这些人大多浪费编码,因为它NoMethodError会产生与生产中完全相同的结果AbstractClassError.


你也不需要/需要Java中的抽象类.这是一种记录它是基类的方法,不应该为扩展类的人实例化.
@fijiaaron:如果你这么认为,那么你肯定不明白抽象基类是什么.他们并没有太多"记录"一个类不应该被实例化(这是一个抽象的副作用).它更多的是为一堆派生类声明一个公共接口,然后保证它将被实现(如果没有,派生类也将保持抽象).它的目标是支持Liskov的替换原则用于实例化没有多大意义的类.
IMO,很少有语言应该限制你的面向对象编程的概念.在特定情况下,什么是合适的,不应该依赖于语言,除非有与性能相关的原因(或更具说服力的东西).

8> Nicklasos..:

你可以尝试3个rubygems:
界面
抽象
简单的抽象

推荐阅读
mobiledu2402851173
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有