2011-07-05 17 views
22

interfaz (Java) que acabo de leer el artículo de Wikipedia sobre duck typing, y siento que me olvido de un punto importante sobre el concepto de interfaz Solía ​​en Java:tipificación de pato y el concepto

"When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck." 


class Duck: 
    def quack(self): 
     print("Quaaaaaack!") 
    def feathers(self): 
     print("The duck has white and gray feathers.") 
    def swim(self): 
     print("Swim seamlessly in the water") 

class Person: 
    def quack(self): 
     print("The person imitates a duck.") 
    def feathers(self): 
     print("The person takes a feather from the ground and shows it.") 
    def name(self): 
     print("John Smith") 

def in_the_forest(duck): 
    duck.quack() 
    duck.feathers() 

def game(): 
    donald = Duck() 
    john = Person() 
    in_the_forest(donald) 
    in_the_forest(john) 

game() 

¿y si, en in_the_forest, escribo:

  • lo hace quack como un pato? sí
  • ¿tiene pato feathers? sí
  • genial, es un pato que tenemos!

y posterior, porque sé que es un pato, lo quiero swim? john se hundirá!

No quiero que mi aplicación falle (aleatoriamente) en el medio de su proceso solo porque John fingió ser un pato, pero supongo que no sería una buena idea verificar cada atributo del objeto cuando lo recibo ...?

+0

+1: pregunta bien presentada – msw

+1

En resumen, no se preocupe. Usted escribe buenas pruebas que cubren tantas rutas de código y casos de esquina como sea humanamente posible, pero el 100% de seguridad nunca es posible. Y tenga en cuenta que no puede tener 100% de seguridad con Java o la mayoría de otros sistemas de tipo estático;) – delnan

+1

+1: una pregunta realmente bien presentada sobre un tema importante, con recuentos con excelentes respuestas. Lo siento, solo puedo darle solo 1 voto positivo. – Dave

Respuesta

19

Duck typing no se trata realmente de verificar si las cosas que necesita están allí y luego usarlas. Duck typing se trata solo de usar lo que necesita.

La función in_the_forest fue escrita por un desarrollador que estaba pensando en patos. Fue diseñado para operar en un Duck. Un Duck puede quack y feathers, por lo que el codificador usó esas características para realizar el trabajo. En este caso, el hecho de que un Duck también puede ser swim no se usó, y no fue necesario.

En un lenguaje estático como Java, in_the_forest habría sido declarado para tomar un Duck. Cuando el codificador descubrió más tarde que tenían un Person (que también podría ser quack y feathers) y quería reutilizar la función, no tuvieron suerte. ¿Es Person una subclase de Duck? No, eso no parece apropiado. ¿Hay una interfaz QuacksAndFeathers? Tal vez, si tenemos suerte. De lo contrario, tendremos que hacer uno, vaya a modificar Duck para implementarlo, y modifique in_the_forest para tomar un QuacksAndFeathers en lugar de un Duck. Esto puede ser imposible si Duck está en una biblioteca externa.

En Python, acaba de pasar a su Persona al in_the_forest y funciona.Porque resulta que in_the_forest no necesita un Duck, solo necesita un objeto "parecido a un pato", y en este caso la Persona es lo suficientemente parecida a un pato.

game embargo, necesita una definición diferente de "parecida a un pato", que es un poco más fuerte. Aquí, John Smith no tiene suerte.

Ahora, es cierto que Java habría detectado este error en tiempo de compilación y Python no. Eso puede verse como una desventaja. El argumento del contador pro-dynamic-typing es decir que cualquier cuerpo sustancial de código que escriba contendrá siempre errores que el compilador no puede capturar (y para ser honesto, Java ni siquiera es un ejemplo particularmente bueno de un compilador con fuerte controles estáticos para atrapar muchos errores). Entonces debes probar tu código para encontrar esos errores. Y si está probando esos errores, encontrará trivialmente errores donde pasó un Person a una función que necesita un Duck. Dado que, dice el mecanógrafo dinámico, un lenguaje que lo tienta a no prueba porque encuentra algunos de sus errores triviales es en realidad un malo cosa. Y además de eso, le impide hacer algunas cosas realmente útiles, como reutilizar la función in_the_forest en un Person.

Personalmente estoy dividido en dos direcciones. Realmente me gusta Python con su tipado dinámico flexible. Y realmente me gusta Haskell y Mercury por sus potentes sistemas de tipo estático. No soy muy fanático de Java o C++; en mi opinión, tienen todos los bits malos de tipeo estático con algunos de los bits buenos.

+4

Algunas personas piensan en tipeo estático como un tipo de sistema integrado de pruebas de unidades, pero yo realmente no te lo pierdasEs como en la vida real: si una persona se despierta en una colección aleatoria de objetos y mira para ver a un pato sentado junto a ellos, algo salió muy mal hace un buen tiempo. – detly

+1

Oh, espera, lo extraño cuando quiero que el autocompletado de Eclipse me muestre cosas útiles. Eso es. – detly

+0

+1 con soapbox gratuito: ¿quieres tipo de seguridad en un idioma poblado por ints? Necesitas los tipos enteros a distancia de Pascal si no quieres ver un pato sentado a tu lado (y nadie quiere enteros a gran distancia (y las enumeraciones hasta 2^16 serían una tontería)) – msw

5

No se puede hablar en otros idiomas, pero en python se ha introducido recientemente (v2.6) el Abstract Base Classes (ABC) module.

Si lee los motivos de su introducción (PEP 3119) rápidamente se dará cuenta de que parte del motivo fue "salvar a John de una muerte segura" o, para facilitar el control del hecho cuando programa en un interfaz, todos los métodos de interfaz estarán allí. Desde el PEP vinculado:

ABC son simplemente clases de Python que se añaden al árbol de herencia de un objeto para señalar ciertas características de que se oponen a un inspector externo. Las pruebas se realizan utilizando isinstance() y la presencia de un ABC particular significa que la prueba ha pasado. Además, los ABC definen un conjunto mínimo de métodos que establecen el comportamiento característico del tipo. El código que discrimina objetos basados ​​en en su tipo ABC puede confiar en que esos métodos siempre estarán presentes.

En general, puede aplicar el mismo patrón para su propio código. Por ejemplo: puede crear una clase BasePlugin con todos los métodos necesarios para que un complemento funcione, y luego puede crear varios complementos diferentes subclassing. Dependiendo de si cada plugin debe o puede definidos por dichos métodos, se puede definir BasePlugin métodos para pasar en silencio (plugins puede definir los métodos) o para lanzar una excepción (plugins deben definir los métodos/anular el BasePlugin uno).

EDIT: En el hilo de comentarios a continuación, se me ha sugerido incluir en la respuesta de este poco de discusión:

Este tipo de características - por lo menos en Python - no se aplican para el El programador humano (Python nunca silencia un error, por lo que ya hay muchos comentarios), sino por la propia capacidad de introspección de Python (lo que facilita la escritura de carga dinámica, código de metaprogramación, etc.). En otras palabras: sé que John no puede volar ... ¡pero quiero que el intérprete de Python también lo sepa! :)

+0

El hecho de que pueda usar Java-isms que simulen la escritura estática no significa que deba hacerlo. Aún no he visto una implementación de clase que no sea de juguete en la que el usuario de una lista heterogénea aún no sepa si John puede volar. Además, suponga que su comprobación 'isinstance' falla, de todos modos tiene que lidiar con ella. ¿Cómo difiere esto de un bloque 'except'? ("La herencia puede ser una de las características más seductoramente usadas de OOP" -me) – msw

+0

@msw - No conozco Java, así que el paralelo no me ayuda a entender mucho tu observación (soy todo oídos si tienes una oportunidad de reformular, sin embargo!). Tenga en cuenta que la mayoría de este tipo de características, al menos en Python, no se implementan por el programador humano (Python nunca silencia un error, por lo que ya hay muchos comentarios), sino por el propio Python. capacidad de introspección (lo que facilita la escritura de carga dinámica, código de metaprogramación, etc.). En otras palabras: sé que John no puede volar ... ¡pero quiero que el intérprete de Python también lo sepa! :) – mac

+0

el intérprete de Python lo sabe. Hubiera recapitulado mi respuesta en http://stackoverflow.com/questions/6576837/is-enforcing-an-abstract-method-implementation-unpythonic/6576986#6576986 pero sentí que estaba siendo dogmático hoy. Mi "Java-ism" podría aplicarse a muchos lenguajes OOP actualmente populares (por ejemplo, C++). Encuentro http://dirtsimple.org/2004/12/python-is-not-java.html útil para romper mentalidades antiguas. Su punto con respecto a la metaprogramación, etc. debería ser más obvio que 'tis al no metaprogramador (pero también debería hacerlo C++ dynamic_casts (¿por qué la función está allí si no se usa;)) – msw

3

Yo no quiero que mi aplicación se bloquee (al azar) en medio de su proceso sólo porque John fingió ser un pato, pero supongo que no sería una buena idea para comprobar cada uno de los atributos del objeto cuando lo recibo ...?

Esa es una cuestión de tipado dinámico en general. En un lenguaje estáticamente tipado como Java, el compilador comprueba en tiempo de compilación si Person implementa IDuck o no. En un lenguaje de tipado dinámico como Python, se obtiene un error en tiempo de ejecución si Person pierde alguna función de pato en particular (como swim). Para citar otro artículo de Wikipedia ("Type system", Section "Dynamic Typing"):

tipado dinámico puede dar lugar a errores de tipo en tiempo de ejecución, es decir, en tiempo de ejecución, un valor puede tener un tipo inesperado, y se aplica una operación sin sentido para ese tipo. Dichos errores pueden ocurrir mucho después del lugar donde se cometió el error de programación, es decir, el lugar donde el tipo incorrecto de datos pasó a un lugar que no debería tener. Esto puede hacer que el error sea difícil de localizar.

La tipada dinámica tiene sus inconvenientes (usted ha mencionado uno) y sus ventajas. Se puede encontrar una breve comparación en otra sección del artículo del sistema Type en Wikipedia: Static and dynamic type checking in practice.

Cuestiones relacionadas