首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在父类中定义一个子类是不是不符合常规?

在父类中定义一个子类是不是不符合常规?
EN

Stack Overflow用户
提问于 2013-02-20 05:27:10
回答 3查看 599关注 0票数 8

像下面这样在父类下定义一个子类是不是很传统?

代码语言:javascript
运行
复制
class Element

  class Div < Element

  end

  class Paragraph < Element

  end

end

或者创建一个包含子类的模块更合适?

代码语言:javascript
运行
复制
class Element

end

module Elements

  class Div < Element

  end

  class Paragraph < Element

  end

end

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

代码语言:javascript
运行
复制
module Element

  class Base

  end

  class Div < Base

  end

  class Paragraph < Base

  end

end

还是强制使用命名约定更好?

代码语言:javascript
运行
复制
class Element

end

class DivElement < Element

end

class ParagraphElement < Element

end

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

哪一个是最好用的?

每种方法的优缺点是什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-02-24 00:12:59

TL;DR:最传统也是最好的方法是使用包含基类及其子类的模块。但是让我们来回顾一下所有的事情。

关于这一点的官方来源并不多;然而,它是一种使用模块来包含库、代码和类组的风格。

超类中的子类

Pros

  • Self-contained:整个类系统包含在一个名称

缺点:

  • Unnatural:谁会想到在超类内部寻找一个子类?

将子类放在超类中确实取决于具体情况。然而,这种方法的任何好处也是通过模块方法实现的。但在实践中,这并没有完成。类在这里包含方法、实例变量、类方法等。但是类可以被认为是嵌套的最后一层--除非是非常特殊的情况,否则类中不会有类。

我能想到的有意义的一种情况是,使用子类的唯一方式是通过超类,例如,具有XMLPDF等内部子类的Formatter类。假设您只通过执行Formatter.new(:xml)等操作来使用这些类。但如果我们这样做,子类应该是私有的,并且无论如何都不能被外部世界访问。在这一点上,继承是一种非常C++y的方式,根本不是Rubyish。

基类在模块外,子类在模块内

优势:

  • 我想不出任何

缺点:

  • 暗示非conected:如果元素与它的子元素不在同一名称空间中,除了名称之外,还有什么能告诉我它是相关的?

这种方法非常不自然。这让它看起来好像Element与它的子代没有任何关系,或者如果换个角度来看,它的子代是内部实现的细节,不需要处理。无论哪种方式,它看起来都像是破旧的、草率的命名和糟糕的代码结构规划。如果我使用这种方法阅读代码,就必须查看Elements模块的内容,才能看到Element被子类化了--这不是最自然的做法。

模块中的类和子类(最佳解决方案)

优势:

  • include:超类和所有的元素类都包含在一个命名空间中,允许它们轻松地导入、请求、迭代等。同时也有助于将这些类轻松地include到任何代码中。
  • Clear:在Element和子类之间有一个明显的关联。它们显然是functionality.

的捆绑包

缺点:

  • 鼓励延迟命名:这确实鼓励您命名像Base这样非常模糊的类。

这是最好的方法。它使类成为一个整洁的捆绑包,同时仍然显示出明显的关联和明显的“在这里,使用我的Div类”(与类中的子类策略相反)。此外,这对元编程非常有帮助,在元编程中,将所有内容都放在一个模块中对于让事情正常工作至关重要。最后,这可以很好地与autoloadrequire_relativeinclude等构造一起工作。这些构造表明,这就是设计语言的使用方式。

强制使用命名约定

优势:

  • Simple: No complexity here.
  • Removes ambiguity:通过将DivPara等短名称转换为DivElementParaElement.

来消除它们的歧义

缺点:

  • :分组类或方法的命名约定应该只存在于没有更好方法的语言中,比如C或Objective-C。在获得namespaces.
  • No编程分组后,C++立即放弃了它:这些命名约定虽然对人类来说很清楚,但对于元编程代码来说,它们使类结构变得非常模糊,并使程序无法将类作为group
  • Pollutes全局命名空间处理:这会在全局命名空间中创建很多很多名称,这始终不是一个好主意。

这是一个非常,,非常糟糕的解决方案。它充斥着编写草率的C风格的代码,几乎没有组织和意义。这些命名约定应该只在没有更好解决方案的语言中使用,而Ruby有很多更好的解决方案。即使在数组中定义所有类也比命名约定更好。

注意:但是,如果您真的想要这样做,您可以在短名称上定义一个命名约定,比如DivPara,只要您仍然将它们保留在一个模块中,那么它就是Elements::DivElement。然而,这违反了DRY,我不建议这样做。

结论

所以,你确实有两个选择。只需将所有内容放在一个模块中:

代码语言:javascript
运行
复制
module Elements
  class Element; end
  class Div < Element; end
  #etc...
end

或者,将所有内容放在一个具有命名约定的模块中:

代码语言:javascript
运行
复制
module Elements
  class Element; end
  class DivElement < Element; end
  #etc...
end

出于清晰度、标准方法的使用和元编程的原因,我建议使用前者。

票数 9
EN

Stack Overflow用户

发布于 2013-02-23 23:00:09

这是我多次遇到的问题-您有一些共享功能和几个使用它的不同实现类-共享功能和实现类的命名空间具有相同的名称是很自然的。

在您的第一个示例中定义父类下的子类时,我从来没有遇到过问题--除了它有时会使我团队中的其他开发人员感到困惑。因此,根据你的合作伙伴和他们的喜好,我认为这种方法不会有任何问题。

如果有一个有意义的名称,我仍然倾向于使用第二种方法,为名称空间使用不同的名称。如果没有,我会使用第一种方法。

我会避免使用像Base这样的名称,因为在我看来,这种泛型名称鼓励您在其中添加任何旧的东西,而描述类的功能的名称将(希望)让您在每次添加方法时考虑它是否真的属于那里。

我真的不喜欢你的命名约定示例中的复合名称,我有一种模糊的感觉,认为这就像数据库规范化-每个字段(或类名)应该只包含一条信息。

不管怎样,我希望这对你有帮助。除了我自己的经验之外,我真的不能从任何来源得出结论(这取决于你是否认为这是“可信的”),因为我确实认为这个问题没有绝对的答案。这在很大程度上是主观的。

票数 3
EN

Stack Overflow用户

发布于 2013-02-20 05:55:46

名称空间和继承的用途不同。使用名称空间将一个模块封装在另一个模块中。使用继承来定义一个模块,使用另一个模块的方法/变量/常量作为默认值。

原则上可能会发生这样的情况:您可能希望一个模块既位于同一个模块的名称空间中,又继承自同一个模块,但这取决于您的用例。如果不讨论特定的用例,就无法确定您提出的方法中哪一种是最好的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14967751

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档