如何实现班级组合

问题描述 投票:0回答:1

嗨,我有一个包含多个项目的模型,现在所有项目都有一组共享属性:id、name、parent。此外,其中一些项目仅用于包含其他项目。有些是为了连接到其他项目等等。在尝试实现这一点时,我可以考虑进行继承,但我也可以考虑进行组合(并且阅读了很多评论说更喜欢这样做)。因此,我可以定义一个具有基本属性的类,其主要工作只是提供访问权限并允许对其进行修改:

from attrs import define, Factory
@define
class BaseProperties:
  identifier: str
  name: str
  parent_id: Optional[str]

@define
class ConnectorItem:
  base_properties: BaseProperties
  connections: "List[ConnectorItems]" = Factory(list)

@define
class ContainerItem:
  base_properties: BaseProperties
  children: "List[Union[ConnectorItem, ContainerItem]]" = Factory(list)

现在的问题是,例如,当我想要访问容器项目的名称或 ID 时,我需要执行以下操作:

container_item.base_properties.identifier

或在 ContainerItem 内定义一个属性。

@property
def identifier(self):
  return self.base_properties.identifier

如果我只想使用:

container_item.identifier

现在第一个选项感觉用户需要了解 ContainerItem 类的内部实现,并且当项目增长时可能会导致使用大量点符号来访问某些成员。

当我基本上需要在包含 BaseProperties 类的每个类中复制粘贴一堆 setter 和 getter 属性时,第二个选项感觉很麻烦。

在这种情况下我应该使用继承而不是组合吗?问题是,即使 ContainerItem 和 ConnectorItem 共享基本属性,我也不会在同一上下文中使用它们,所以我认为在这种情况下不需要多态性,只是基本的代码可重用性。

实现这种情况的更好方法是什么,知道这是一个简化版本,实际上 ConnectorItem 可能由不同的类组成,以获得不同的 ConnectorItemType。

python inheritance composition python-attrs
1个回答
0
投票

您在这里所做的是严格的专业化,这是通过子类进行代码共享的一个很好的理由。这实际上并不是一个 attrs 问题,而是一个更广泛的 Python 和软件工程主题。

我过去曾在博客中讨论过这个主题,我专门解决了这种情况:https://hynek.me/articles/python-subclassing-redux/(您的主题从“类型 3:专业化”开始,但我建议阅读其余部分以了解上下文)。如果您更喜欢视频,我也在 PyCon US 2023 上就此发表了演讲:https://www.youtube.com/watch?v=k8MT5liCQ7(主题从 37:33 开始,同样的警告)。

放弃一件事:你试图解决的问题甚至可以在我们不在这里子类化的 Go 中实现,他们称之为 embedding

© www.soinside.com 2019 - 2024. All rights reserved.