【问题标题】:Parent methods which return child class instances返回子类实例的父方法
【发布时间】:2014-09-25 08:18:09
【问题描述】:

返回子类实例作为父类实例方法的输出是不好的做法,如果是,为什么?

例如,可以如下--

class Parent(object):
    def __init__(self, attr):
        self.attr = attr

    def child(self, typ):
        if typ == 'a':
            return ChildA(self.attr)
        else:
            return ChildB(self.attr)

class ChildA(Parent):
    pass

class ChildB(Parent):
    pass

做一个好的设计?

【问题讨论】:

  • 这不是见仁见智吗?我们不知道对 Stack Overflow 有意见。
  • 我在想关于软件设计的“什么是好的实践”的问题是可以接受的。在 SO 中搜索“良好实践”,您会发现很多高票的问题,即使并不总是很清楚是否有明确的答案。
  • 其中大部分来自“旧的” Stack Overflow,大多数(应该)已经关闭。

标签: python class oop


【解决方案1】:

如果有更多知识渊博的人回答这个问题,我将不胜感激,但由于这还没有发生,我将投入两美分的价值。


我认为这确实不是一个好习惯。出于多种原因,父类不应直接引用子类:

  • 首先,它阻碍了模块的未来扩展。每当引入新的子类时,可能还需要更新父类,以便在其实现中考虑这个新的子类。这打破了SOLID principles of object-oriented programmingopen-closed principle

  • 另一个缺点,至少在 Python 中是这样,它强制所有子类在同一个文件中定义,以避免循环导入。

  • 此外,由于指定的方法是由子类继承的,除非它被重写,否则它会触发“兄弟”类之间的某种熟悉,这可能是不希望的。

虽然可以通过一些编码工作来规避技术问题,但这种方法不必要地给程序员带来了额外的负担。

我确信在某些情况下,让父类了解其子类似乎很有用,但我认为一般来说,这种情况会推断出设计错误和替代解决方案'不涉及这种自省应该受到追捧。

请注意,这并不意味着父对象不应使用子对象。与所有其他对象一样,子对象可以合法地作为参数接收或由其父对象的方法返回。父对象的方法甚至可以将它们视为普通的父对象,因为子对象也是父对象,这是面向对象编程的主要支柱之一。


关于您的特定示例,请考虑factory design pattern。例如:

class Parent(object):
    def __init__(self, attr):
        self.attr = attr

class ChildA(Parent):
    pass

class ChildB(Parent):
    pass

class Factory(object):
    def __init__(self, parent):
        self.parent = parent

    def create(self, <some_external_data>):
        if <an algorithm that determines the desired type based
            on some_external_data and the state of the parent>:
            return ChildA(parent.attr)
        else:
            return ChildB(parent.attr)

【讨论】:

  • 在我的例子中,我想为文件解析器创建一个工厂模式,问题是我不知道你传递给 create 方法的类型,问题是父类“Parser”有这个功能决定什么是基于扩展检索的文件类型,我应该在哪里定义这个方法?在工厂班?我认为它应该在 Parser 类本身中是无效的,你能指导@yoel吗?
  • 首先,工厂类可以在其__init__() 方法或create() 方法中接收父对象。然后,在其create() 方法中,它应调用父级的方法来检索扩展。最后,在其create() 方法中,它应使用基于检索到的扩展名的某种算法来确定所需的孩子类型。
猜你喜欢
  • 2015-05-23
  • 1970-01-01
  • 1970-01-01
  • 2021-08-28
  • 2022-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多