如何在不首先在Ruby中实例化的情况下获取所有子类的列表

use*_*152 8 ruby ruby-on-rails

如果我有4个具有以下层次结构的类:

class MainClass < ActiveRecord::Base
  ...
end

class SubClassA < MainClass
  ...
end

class SubClassB < MainClass
  ...
end

class SubClassC < MainClass
  ...
end
Run Code Online (Sandbox Code Playgroud)

如何在不经过并创建其他每个类的实例的情况下获取MainClass的子类列表?

在一个新的IRB会议中,我可以进去说

irb(main)> MainClass.descendants
=> []
Run Code Online (Sandbox Code Playgroud)

但是,如果我经历并创建每个子类的实例,我将看到以下内容

irb(main)> SubClassA.new
=> #<SubClassA ...>
irb(main)> SubClassB.new
=> #<SubClassB ...>
irb(main)> SubClassC.new
=> #<SubClassC ...>
irb(main)> MainClass.descendants
=> [SubClassA(...), SubClassB(...), SubClassC(...)]
Run Code Online (Sandbox Code Playgroud)

我基本上是在寻找一种方法来提供所有子类的方法,以便将来当我想添加SubClassD,SubClassE等时,我不必担心每个人都会在代码中实例化,然后用户才能看到它们.

Fre*_*ung 9

这是一个开发模式的假象,只在第一次引用时加载类:那些文件还没有被解释器读取 - 就ruby而言,这些类真的还不存在

解决方法是放置

require_dependency "subclass_a"
require_dependency "subclass_b"
....
Run Code Online (Sandbox Code Playgroud)

在底层主类的文件(在类定义之外)

  • 这个解决方案RAILS具体吗? (2认同)

Cyz*_*far 8

有几种方法可以实现这一目标.通过使用诸如descendants_tracker之类的gem :

class MainClass < ActiveRecord::Base
  extend DescendantsTracker
end

class SubClassA < MainClass 
end

...

MainClass.descendants # => [SubClassA]
Run Code Online (Sandbox Code Playgroud)

或者你可以在你的父类中创建一个自定义的,如下所示:

class  MainClass < ActiveRecord::Base
  def self.descendants
    ObjectSpace.each_object(Class).select { |klass| klass < self }
  end
end

class SubClassA < MainClass 
end

class SubClassB  < MainClass 
end

puts MainClass.descendants 

#=> SubClassA
    SubClassB  
Run Code Online (Sandbox Code Playgroud)

您还可以检查依赖关系的级别.例如,如果你想要一个MainClass的直接子数组,你可以使用.subclasses类方法

MainClass.subclasses  # => [SubClassA, SubClassB,...]
Run Code Online (Sandbox Code Playgroud)

现在,如果您想要多个级别的子类使用.descendants.你可以在这里找到一个例子