【问题标题】:What would be the most efficient way to set up classes that belong to a class设置属于某个类的类的最有效方法是什么
【发布时间】:2017-04-03 21:29:46
【问题描述】:

您将如何设置以下类结构,为什么?

类 Person 代表一个人 教室代表一个房间

我想在哪里存储人的房间位置,并能够有效地提出以下两个问题:

1) X 在哪个房间?和, 2) Y 房间里有哪些人?

我能看到的选项是:

  • Class Person 存储 Room 位置(问题 2 效率低下),
  • Class Room 存储其 Persons(问题 1 效率低下),
  • 以上两者(数据完整性问题的机会)以及,
  • 外部字典保存数据(似乎违背 OOP 的精神)

【问题讨论】:

  • “最佳”方式?那是什么意思?不要迂腐,但工程师在使用“最佳”这个词之前应该总是三思而后行。如果没有价值体系,这个词是没有意义的,如果留下隐含的价值体系,答案就会模棱两可。相反,您可以问:“以下哪种设计在存储空间方面最有效?”或者“以下哪种设计会产生最易读的代码?”或者简单地说,“你会怎么做,为什么?”
  • @JohnWu 你是对的。在这种情况下,我一直在寻找一些主观的答案,所以我会选择“你会怎么做,为什么?”。感谢回复!

标签: python class oop


【解决方案1】:

绝对是一个外部结构。这就是 OOP 的精神。类代表对象。一个人既不是房间的财产,房间也不是人的财产,因此没有理由将一个人归入另一个班级。相反,字典表示它们之间的关系,因此它应该是一个新实体。

一个简单的格式是一个字典,其中每个键是一个房间,值是其中的人员列表。但是,如果您需要更复杂的功能,您可能可以围绕它创建一个类

【讨论】:

  • 恕我直言,您似乎错了一个人都不是房间的财产,反之亦然。它不是财产,但 OP 的域可能需要人和房间关联,因为这就是现实生活中的业务运作方式:D
  • 我同意最好的结构取决于对其进行的操作。尽管如此,原则上,我认为除非真的需要,否则不应将关联存储在实体中。将人与房间相关联会降低两者的可重用性,并且可能会损害可伸缩性(添加实体和关系时会发生什么?我们是否必须修改所有现有类?)添加关系
  • 在这样的 big 项目中,您将定义一个基类,并且每个域都可以将关联添加到 Room 和 Person 特化。因此,核心 Room 和 Person 本身没有关联,但它可能取决于域。
  • @blue_note 感谢您的回复 - 我喜欢外部字典的想法 - 根据Wikipedia's article on object composition,将值作为 Person 指针听起来像是正确答案
【解决方案2】:

外部字典保存数据(似乎违背 OOP 的精神)

或者也许您可以一次实现所有方法:您定义两个关联 Person has a RoomRoom has many people,并且您还使用适当的数据索引所有内容以光速访问您的对象的结构!

也就是说,您可以使用面向对象的关联(即组合)遍历您的对象图,并实现一些特定的要求,将您的图存储在一些数据结构中以满足您的要求。

这并不违背 OOP 的精神。它支持良好的编码实践,而不是人为的教条。

【讨论】:

  • 感谢马蒂亚斯的回答!当您说定义这两个关联时,您是说在外部结构级别、类级别还是仅在概念上定义它?如果我想帮助一个人移动房间,我想我会使用聚合而不是组合?另外,当您提到使用索引和适当的数据结构实现特定要求时,您是在谈论外部字典结构吗?这可能在 python 中还是我必须将值存储在数据库中?
  • @Harlekuin 好吧,AFAIK 聚合是一种组合形式!所以是的,我会实现它,以便访问分配给给定人员的房间,而不会比获取聚合更麻烦和噪音。另一方面,当我向您解释可以索引您的数据时,我的意思是您可以在程序或系统的某些部分中使用 Python 中的字典、集合、列表等数据结构来加速在某些条件下对对象的访问.
  • @Harlekuin 这样您可以避免查询整个对象集合,但这些对象已经以您只需要列出它们的方式存储。
  • @Harlekuin 似乎您可以轻松地将所有人存储在字典中,其中键可以是 Person.id 并评估这些人。还有一个房间字典。所以你可以立即获取一个人或一个房间(O(1))并分别获取它们的聚合
【解决方案3】:

并非所有问题都适合 OOP。这是其中之一。 :-)

这里基本上是一个二维网格或矩阵。 一根轴代表人,另一根轴代表房间。限制是一个人只能在一个房间里。

(person, room) 元组的list 似乎是用 Python 表示这一点的好方法。这是一个示例(在 IPython 中),带有您的两个查询:

In [1]: locations = [('alfred', 'office'), ('ben', 'storage'), ('charlene', 'office'), ('deborah', 'factory')]

In [2]: [room for person, room in locations if person == 'charlene']
Out[2]: ['office']

In [3]: [person for person, room in locations if room == 'office']
Out[3]: ['alfred', 'charlene']

查询是列表推导,所以它们非常快。 除非您的位置列表巨大,否则我认为性能不会是一个大问题。

请注意,此解决方案适用于空房间和不在场的人员。

In [4]: [room for person, room in locations if person == 'zeke']
Out[4]: []

In [5]: [person for person, room in locations if room == 'maintenance']
Out[5]: []

您必须注意不要两次插入同一个人。

【讨论】:

  • 感谢罗兰的回复!我认为即使在多对多关系中,只要相同的组合不重复,元组列表仍然可以工作。如果我必须使用上述类,我仍然可以使用指向 Person 和 Room 对象的指针的方法,这将利用您的简洁查询(即 Person.name == 'charlene')
  • @Harlekuin 为了方便起见,我使用了字符串。您可以使用任意 Python 对象。
  • 哦,对了,抱歉 Roland,我想当你说“不是每个问题都适合 OOP”时,你的意思是我不应该使用类来解决这个问题
  • 类层次结构非常适合某些问题,但非常适合其他问题。通常 Python 的内置数据结构可以很好地解决问题。我喜欢在可能的情况下使用namedtupletuple 子类来制作不可变对象,这样我就不会误将它们搞砸了。
猜你喜欢
  • 2017-11-25
  • 1970-01-01
  • 1970-01-01
  • 2022-09-28
  • 2019-02-10
  • 2016-03-28
  • 2012-09-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多