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
似乎每个库都选择不同的命名空间/命名约定.
哪个最好用?
各自的优点和缺点是什么?
解决方法
@H_502_24@ TL; DR:最常用和最好的方法是使用包含基类及其子类的模块.但是,让我们重温一切.这方面的官方消息来源不多;但是,使用模块来包含库,代码和类组是一种风格.
超类中的子类
优点:
>自包含:整个类系统包含在一个名称下
缺点:
>不自然:谁会想到在超类中查找子类?
将子类置于超类中实际上取决于具体情况.但是,该方法的任何好处也可通过模块方法实现.但实际上,这还没有完成.类在这里包含方法,实例变量,类方法等.但是类可以被认为是最后一级嵌套 – 除非是非常特定的情况,否则类中没有类.
我能想到这个有意义的一种情况是,使用子类的唯一方法是通过超类,例如具有内部子类(如XML,PDF等)的Formatter类.假设您只使用这些类通过做Formatter.new(:xml)之类的事情.但是如果我们这样做,子类应该是私有的,无论如何都不能被外界访问.在这一点上,继承是一种非常方式,而不是Rubyish.
基类外部模块,子类内部
优点:
>我想不出任何
缺点:
> Implies Non-conected:如果Element与其子元素不在同一个命名空间中,超出名称的内容告诉我它甚至是相关的?
这种方法非常不自然.它使得它看起来好像Element与它的孩子没有任何关系,或者如果用不同的方式看,它的子项是内部实现细节,不需要处理.无论哪种方式,它看起来像破旧,草率命名和糟糕的代码结构规划.如果我使用它来阅读代码,我必须查看Elements模块的内容,看看Element是否已经被子类化了 – 这不是最自然的事情.
模块中的类和子类(最佳解决方案)
优点:
> Contained:超类和所有Element类都包含在一个名称空间中,允许它们轻松导入,需要,迭代等.还有助于元编程.
> Includable:这些类可以很容易地包含在任何代码中.
>清除:Element和子类之间存在明显的关联.它们显然是一组功能.
缺点:
>鼓励懒惰的命名:这确实鼓励你为像Base这样非常模糊的类命名.
这是最好的方法.它使类成为一个整洁的包,同时仍然显示一个明显的关联和明显的“在这里,使用我的Div类”(而不是类中的子类策略).此外,这对于元编程非常有用,其中包含模块中的所有内容对于使事情有效至关重要.最后,这适用于autoload,require_relative,include等构造.这些表明这是语言的设计方式.
强制命名约定
优点:
>简单:这里没有复杂性.
>消除歧义:通过将它们转换为DivElement和ParaElement来消除Div或Para等短名称的歧义.
缺点:
> Archaic:组类或方法的命名约定只应存在于没有更好方法的语言中,例如C或Objective-C.一旦获得名称空间,C就会删除它.
>没有编程分组:这些命名约定虽然对人类很清楚,但是对于元编程代码来说,类结构非常混浊,并且使得程序无法作为一个组来处理类.
>污染全局命名空间:这会在全局命名空间中创建许多名称,这总是一个坏主意.
这是一个非常非常糟糕的解决方案.它包含了编写草率,C风格的代码,几乎没有组织和意义.这些命名约定只能用于没有更好解决方案的语言,Ruby有很多更好的解决方案.即使定义数组中的所有类也比命名约定更好.
注意:但是,如果您真的想要,可以在Div或Para等短名称上定义命名约定,只要您仍然将它们保存在模块中,这样它就是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
为了清晰,使用标准方法和元编程原因,我采用前者.