ruby - 在其父类中定义子类是否非常规?

标签 ruby

像下面这样在其父类下定义子类是惯例吗?

class Element

  class Div < Element

  end

  class Paragraph < Element

  end

end

还是让模块包含子类更合适?
class Element

end

module Elements

  class Div < Element

  end

  class Paragraph < Element

  end

end

或者在一个模块中创建一个“基”类并在同一个模块中定义子类?
module Element

  class Base

  end

  class Div < Base

  end

  class Paragraph < Base

  end

end

或者强制命名约定更好?
class Element

end

class DivElement < Element

end

class ParagraphElement < Element

end

似乎每个库都选择不同的命名空间/命名约定。

哪个最好用?
各自的优缺点是什么?

最佳答案

TL;博士 :最传统和最好的方法是使用包含基类及其子类的模块。但让我们回顾一下一切。
这方面的官方消息来源并不多;然而,使用模块来包含库、代码和类组是一种风格。
父类(super class)中的子类
优点 :

  • 自包含:整个类(class)系统包含在一个名称下

  • 缺点:
  • 不自然:谁会想到在父类(super class)中查看子类?

  • 在父类(super class)中拥有子类实际上取决于情况。然而,这种方法的任何好处也可以通过模块方法来实现。但在实践中,这并没有完成。类在这里包含方法、实例变量、类方法等。但是类可以被认为是嵌套的最后一层——除非是非常特殊的情况,否则类中没有类。
    我认为这有意义的一种情况是使用子类的唯一方法是通过父类(super class),例如 Formatter具有内部子类的类,如 XML , PDF等。假设您仅通过执行 Formatter.new(:xml) 之类的操作来使用这些类。 .但是如果我们这样做,子类应该是私有(private)的,并且无论如何都不能被外界访问。在这一点上,继承是一种非常 C++y 的方式,而不是 Rubyish。
    模块外的基类,内的子类
    优点:
  • 我想不出任何

  • 缺点:
  • 暗示未连接:如果 Element 与其子元素不在同一个命名空间中,那么除了名称之外还有什么告诉我它甚至相关?

  • 这种方法非常不自然。它看起来好像Element与它的子级无关,或者如果换个角度来看,它的子级是不需处理的内部实现细节。无论哪种方式,它看起来都像是破旧、草率的命名和糟糕的代码结构规划。如果我使用它阅读代码,我必须查看 Elements 的内容。模块看到Element根本就被子类化了——这不是最自然的事情。
    模块中的类和子类(最佳解决方案)
    优点:
  • 包含:父类(super class)和所有 Element 类都包含在一个命名空间中,允许它们轻松导入、需要、迭代等。还有助于元编程。
  • 包括:类(class)很容易include编入任何代码。
  • 明确:Element之间存在明显关联和子类。它们显然是一组功能。

  • 缺点:
  • 鼓励懒惰的命名:这确实鼓励您为类命名,例如 Base这是非常模棱两可的。

  • 这是最好的方法。它使类成为一个整洁的包,同时仍然显示出明显的关联和明显的“在这里,使用我的 Div 类”(与子类中的策略相反)。此外,这对于元编程真的很有帮助,在元编程中,将所有内容都放在一个模块中对于使事情正常工作至关重要。最后,这适用于像 autoload 这样的结构。 , require_relative , include等。这些表明这就是语言被设计用来使用的方式。
    强制命名约定
    优点:
  • 简单:这里没有复杂性。
  • 消除歧义:消除短名称的歧义,如 DivPara通过将它们变成 DivElementParaElement .

  • 缺点:
  • 古老的:对类或方法进行分组的命名约定应该只存在于没有更好方法的语言中,例如 C 或 Objective-C。 C++ 获得命名空间后立即删除它。
  • 没有编程分组:这些命名约定虽然对人类来说很清楚,但使得元编程代码的类结构非常困惑,并且使得程序无法将类作为一个组来处理
  • 污染全局命名空间:这会在全局命名空间中创建很多很多名称,这总是一个坏主意。

  • 这是一个非常,非常不好的解决方案。它鼓励编写缺乏组织和意义的草率、C 风格的代码。这些命名约定应该只在没有更好解决方案的语言中使用,而 Ruby 有很多更好的解决方案。即使在数组中定义所有类也比命名约定好。
    注意:然而,如果你真的想要,你可以定义一个短名称的命名约定,如 DivPara只要你仍然将它们保存在一个模块中,那么它就是 Elements::DivElement .但是,这违反了 DRY,我不建议这样做。
    结论
    所以,你真的有两个选择。只需将所有内容放在一个模块中:
    module Elements
      class Element; end
      class Div < Element; end
      #etc...
    end
    
    或者,将所有内容放在具有命名约定的模块中:
    module Elements
      class Element; end
      class DivElement < Element; end
      #etc...
    end
    
    出于清晰、标准方法的使用和元编程的原因,我建议使用前者。

    关于ruby - 在其父类中定义子类是否非常规?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14967751/

    相关文章:

    jquery - Rails,发送 json 参数

    ruby - Bundle 不能与 rbenv 一起使用并且不能 gem install bundler

    ruby-on-rails - Redmine - 安装mysql2(0.3.16)时出错,Bundler无法继续

    ruby - 使用 Capybara SitePrism 等待图像加载

    ruby - 如何在 Ruby 中正确使用 for 循环?

    ruby - 拒绝将信息存储在文件中

    ruby - 如何在给定年份,月份,星期几和它落在 ruby 中的一周的情况下找到日期编号

    ruby-on-rails - 在 Heroku 上的 Rails 中一次显示大量记录

    Ruby 与数组元素的组合

    ruby-on-rails - Windows 上的 Ruby/Rails 前纪元日期