Ruby on rails 子类的循环依赖关系
假设我们使用的是Rails或者仅仅是Ruby on rails 子类的循环依赖关系,ruby-on-rails,ruby,circular-dependency,activesupport,Ruby On Rails,Ruby,Circular Dependency,Activesupport,假设我们使用的是Rails或者仅仅是ActiveSupport::Dependenciesmodule。现在让我们看看这段代码: animal.rb class Animal CHILD = { cat: Cat } # factory!? def self.child(name) CHILD[name].new end end cat.rb class Cat < Animal end 该代码将导致aB不是类(TypeError)(actives
ActiveSupport::Dependencies
module。现在让我们看看这段代码:
animal.rb
class Animal
CHILD = {
cat: Cat
}
# factory!?
def self.child(name)
CHILD[name].new
end
end
cat.rb
class Cat < Animal
end
该代码将导致aB不是类(TypeError)
(activesupport 3.x)或自动加载常量B(activesupport 4.x)时检测到的循环依赖项,因为它尚未创建,但类的名称已在类表中
要解决此问题,可以要求“a”
,然后a
将要求B
能否为以下问题提供更好的解决方案?因此,为了避免在Rails初始化或加载特定类时自动加载大量其他类,Rails使用字符串指定关联的类名(如果需要指定),例如
has_many :published_posts, class_name: 'Post'
因为联想最容易产生这样的互动
因此,如果您可以控制自己使用的内容,并且可以通过使用字符串保存常量的名称直到需要对其进行常量化,从而延迟常量的加载,直到Ruby/Rails中需要它,那么这可能不是一个坏主意。但是,像任何事情一样,最佳解决方案取决于您的需求
如果您来自另一种编程语言背景(如Java),至少在历史上,由于开销(至少在旧版本中)的原因,开发人员会避免使用反射从字符串动态实例化类,那么这似乎很奇怪以及稍后加载类时出错的可能性,而不是在启动时尽早捕获它们。但是,这真的不是一件坏事。而且这也不会阻止您提前急切地加载,因为它实际上是在消除加载过程中由常量引用引起的直接依赖性。因此,为了避免在Rails初始化或加载特定类时自动加载大量其他类,如果需要指定,Rails使用字符串指定关联的类名,例如
has_many :published_posts, class_name: 'Post'
因为联想最容易产生这样的互动
因此,如果您可以控制自己使用的内容,并且可以通过使用字符串保存常量的名称直到需要对其进行常量化,从而延迟常量的加载,直到Ruby/Rails中需要它,那么这可能不是一个坏主意。但是,像任何事情一样,最佳解决方案取决于您的需求
如果您来自另一种编程语言背景(如Java),至少在历史上,由于开销(至少在旧版本中)的原因,开发人员会避免使用反射从字符串动态实例化类,那么这似乎很奇怪以及稍后加载类时出错的可能性,而不是在启动时尽早捕获它们。但是,这真的不是一件坏事。而且,这也不会阻止您提前急切地加载,因为它实际上是在消除加载过程中由常量引用引起的直接依赖。如果您不想/不能使用require
,则应避免循环依赖。避免它们的一种方法是用运行时级调用替换类加载级调用:
class Animal
CHILD = {
cat: 'Cat'
}
def self.child(name)
CHILD[name].constantize.new
end
end
实际上,self.child
现在不能在类级别调用,否则您将再次处于循环依赖上下文中。如果您不想/不能使用require
,则应避免循环依赖。避免它们的一种方法是用运行时级调用替换类加载级调用:
class Animal
CHILD = {
cat: 'Cat'
}
def self.child(name)
CHILD[name].constantize.new
end
end
实际上,self.child
现在不能在类级别调用,否则您将再次处于循环依赖上下文中。您能更好地了解您打算做什么吗?一般来说,我想不出为什么一个类需要知道它自己的子类。循环引用很麻烦,除非你有一个特定的用例需要它。通常,这个问题可以通过其他方式解决-循环依赖需要什么?@dsatch,我正在设置父类中的子类的映射哈希常量。作为一个解决方案,我可以将常数移动到使用它的方法,但我认为这不是一个合适的方法。我只是意识到这只是一个工厂模式。但是无论如何,我想上面的解决方案是最好的解决方案:CONST在类级别(它可以重用),而child
方法是一个工厂方法,用于构造正确的类。你能更好地了解你打算做什么吗?一般来说,我想不出为什么一个类需要知道它自己的子类。循环引用很麻烦,除非你有一个特定的用例需要它。通常,这个问题可以通过其他方式解决-循环依赖需要什么?@dsatch,我正在设置父类中的子类的映射哈希常量。作为一个解决方案,我可以将常数移动到使用它的方法,但我认为这不是一个合适的方法。我只是意识到这只是一个工厂模式。但无论如何,我想上面的解决方案是最好的解决方案:CONST在类级别(可以重用),而child
方法是一个工厂方法,用于构造正确的类。很好,但在我的示例中,我使用的是ActiveAdmin,即在通过路由初始化模型之后立即初始化模型。我已经将我的示例更新为更现实的用例。谢谢!是的,因为你改变了问题,我的答案看起来不正确,但会保持原样。基本上,这个想法是为了避免循环依赖,可以将常量存储为字符串,并在类加载后的某个时间进行常量化。你甚至可能想在常量化之后缓存/存储常量,如果它能提高效率的话。很好,但在我的示例中,我使用的是ActiveAdmin,即在通过路由初始化之后立即初始化模型。我已经将我的示例更新为更现实的用例。谢谢!是的,自从