Python: ¿Debería usar delegación o herencia aquí?

Estoy pensando si debería usar la herencia o la delegación para implementar una especie de clase contenedora. Mi problema es así: Digamos que tengo una clase llamada Python.

class Python:

    def __init__(self):
        ...

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

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

... y mucho más comportamiento. Ahora tengo un código existente que espera un Anaconda, que es casi como un Python, pero ligeramente diferente: algunos miembros tienen nombres y parámetros ligeramente diferentes, otros miembros agregan nuevas funciones. Realmente quiero reutilizar el código en Python. Por lo tanto, podría hacer esto con la herencia:

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"""
        ...

Por supuesto que también puedo llamar. Anaconda().sleep(). Pero aquí está el problema: hay un PythonFactory que necesito usar.

class PythonFactory:

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

quiero que haga un Python y luego debería poder convertirlo en un Anaconda:

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

En este caso, la delegación sería el camino a seguir. (No sé si esto se puede hacer usando la herencia):

class Anaconda:

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

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


    def devourCrocodile(self, croc):
        ...

Pero con la delegación, no puedo llamar Anaconda().sleep().

Entonces, si todavía estás conmigo, mis preguntas son:

A) En un caso similar a este, donde necesito

  • añadir alguna funcionalidad
  • cambiar el nombre de alguna funcionalidad
  • use la funcionalidad de "clase base" de lo contrario
  • convertir objeto "clase base" en objeto "subclase"

¿Debo usar herencia o delegación? (¿O algo mas?)

B) Una solución elegante sería usar delegación más algún método especial que reenvíe todos los accesos a atributos y métodos que Anaconda no responde a su instancia de Python.

preguntado el 22 de mayo de 12 a las 15:05

No entiendo por qué no tienes una clase base común. -

Simplemente no tengo uno. Estoy escribiendo sobre "Anaconda", "Python" y "PythonFactory" es un código existente que no puedo modificar. Estoy entre conjuntos de código existente y necesito "adaptar" uno al otro. -

¿Quién va a usar tus objetos de serpiente? ¿Qué interfaz o interfaces espera de los objetos? ¿Cómo se relacionan las interfaces entre sí? -

La interfaz que debe proporcionar "Anaconda" está determinada por una base de código existente que estoy reimplementando (tratando de mantener el código similar). -

Is Anaconda se supone que también snake() or , solamente wriggle() y negarse a snake() como si no estuviera implementado? -

1 Respuestas

B) Una solución elegante sería usar delegación más algún método especial que reenvíe todos los accesos a atributos y métodos a los que Anaconda no responde a su instancia de Python.

Esto es simple en Python, solo define __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)

Consulte los documentos de Python en __getattr__

Respondido 16 Feb 17, 09:02

Nota al margen: el patrón de diseño del adaptador parece ser una solución ideal para el problema planteado en la pregunta. Está relacionado con la delegación, pero más específico. la respuesta de mensi es una implementación de Python de un adaptador... aunque la declaración explícita de wriggle() en esa forma es innecesario (a menos que su cuerpo deba llamar self.python.snake()). +1 :) - Walter

@Walter Eso es en realidad lo que hace la fuente de la pregunta, así que asumiendo un descuido menor, lo corregí. Lo que queda es la cuestión de si la Anaconda también se permite directamente snake(), De lo contrario def snake(self): raise NotImplementedError() puede ser necesario (o return NotImplemented? Aunque eso podría causar Python.snake para ser evaluado después de todo...) - Tobias Kienzler

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.