【问题标题】:Python: Should I use delegation or inheritance here?Python:我应该在这里使用委托还是继承?
【发布时间】:2012-05-29 02:06:19
【问题描述】:

我正在考虑是否应该使用继承或委托来实现一种包装类。我的问题是这样的:假设我有一个名为Python 的类。

class Python:

    def __init__(self):
        ...

    def snake(self):
        """ Make python snake through the forest"""
        ...

    def sleep(self):
        """ Let python sleep """
        ...

... 以及更多行为。现在我有一个需要Anaconda 的现有代码,它几乎就像Python,但略有不同:一些成员的名称和参数略有不同,其他成员添加了新功能。我真的很想重用Python 中的代码。因此我可以通过继承来做到这一点:

class Anaconda(Python):

    def __init__(self):
        Python.__init__(self)

    def wriggle(self):
        """Different name, same thing"""
        Python.snake(self)

    def devourCrocodile(self, croc):
        """ Python can't do this"""
        ...

当然我也可以拨打Anaconda().sleep()。但问题是:我需要使用 PythonFactory

class PythonFactory:

    def makeSpecialPython(self):
        """ Do a lot of complicated work to produce a special python"""
        …
        return python

我希望它生成Python,然后我应该能够将其转换为Anaconda

myAnaconda = Anaconda(PythonFactory().makeSpecialPython())

在这种情况下,委托将是可行的方法。 (我不知道这是否可以使用继承来完成):

class Anaconda:

    def __init__(self, python):
        self.python = python

    def wriggle(self):
        self.python.wriggle()


    def devourCrocodile(self, croc):
        ...

但是有了委托,我不能打电话给Anaconda().sleep()

所以,如果你还在我身边,我的问题是:

A)在类似的情况下,我需要

  • 添加一些功能
  • 重命名一些功能
  • 否则使用“基类”功能
  • 将“基类”对象转换为“子类”对象

我应该使用继承还是委托? (或者别的什么?)

B) 一个优雅的解决方案是使用委托加上一些特殊的方法,该方法将Anaconda 不响应其Python 实例的所有属性和方法访问转发。

【问题讨论】:

  • 我不明白你为什么没有一个通用的基类。
  • 我只是没有。我正在写“Anaconda”、“Python”和“PythonFactory”是我无法修改的现有代码。我介于现有代码集之间,需要将一个“适应”到另一个。
  • 谁会使用你的蛇对象?他期望对象有什么接口或接口?这些接口是如何相互关联的?
  • “Anaconda”应该提供的接口由我正在重新实现的现有代码库确定(试图保持代码相似)。
  • Anaconda 也应该是snake() 还是 wriggle() 并拒绝snake(),就好像它没有实现一样?

标签: python oop inheritance python-3.x delegation


【解决方案1】:

B) 一个优雅的解决方案是使用委托加上一些特殊的方法来转发 Anaconda 不响应其 Python 实例的所有属性和方法访问。

这在Python中很简单,只要定义__getattr__:

class Anaconda:

    def __init__(self, python):
        self.python = python

    def wriggle(self):
        self.python.snake()


    def devourCrocodile(self, croc):
        ...

    def __getattr__(self, name):
        return getattr(self.python, name)

请参阅__getattr__ 上的 Python 文档

【讨论】:

  • 旁注:适配器设计模式似乎是问题中提出的问题的理想解决方案。它与委托有关,但更具体。 mensi 的答案是适配器的 Python 实现......尽管以这种形式显式声明 wriggle() 是不必要的(除非它的主体应该调用 self.python.snake())。 +1 :)
  • @Walter 这实际上就是问题来源的作用,所以假设有一点疏忽,我更正了它。剩下的问题是Anaconda是否也可以直接snake(),否则def snake(self): raise NotImplementedError()可能是必要的(或return NotImplemented?尽管这可能会导致Python.snake最终被评估......)跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-01
  • 1970-01-01
  • 2018-04-02
  • 2011-07-12
  • 1970-01-01
相关资源
最近更新 更多