php interfaz - ¿Hay algún punto para las interfaces en los lenguajes dinámicos?





abstracta uso (15)


Tenía la impresión de que Python no tiene interfaces . Hasta donde sé, en Python no se puede aplicar un método que se implemente en tiempo de compilación precisamente porque es un lenguaje dinámico.

Hay bibliotecas de interfaz para Python, pero no he usado ninguna de ellas.

Python también tiene Mixins por lo que podría haber creado una clase de interfaz definiendo un Mixin que tenga un pass para cada implementación de método, pero eso realmente no le está dando mucho valor.

En lenguajes estáticos como Java necesita interfaces porque de lo contrario el sistema de tipos simplemente no le permitirá hacer ciertas cosas. Pero en lenguajes dinámicos como PHP y Python, solo aproveche la tipificación de pato .

PHP admite interfaces. Ruby y Python no los tienen. Entonces puedes vivir felizmente feliz sin ellos.

He estado trabajando principalmente en PHP y nunca he utilizado la capacidad de definir interfaces. Cuando necesito un conjunto de clases para implementar cierta interfaz común, entonces simplemente lo describo en la documentación.

¿Entonces, qué piensas? ¿No estás mejor sin usar interfaces en lenguajes dinámicos?




Las interfaces en realidad agregan cierto grado de flexibilidad dinámica similar a lang a los lenguajes estáticos que las tienen, como Java. Ofrecen una forma de consultar un objeto para el cual implementa contratos en tiempo de ejecución .

Ese concepto se integra bien en los lenguajes dinámicos. Dependiendo de su definición de la palabra "dinámico", por supuesto, eso incluso incluye Objective-C, que hace uso de Protocolos bastante extensamente en Cocoa.

En Ruby puede preguntar si un objeto responde a un nombre de método dado. Pero esa es una garantía bastante débil de que hará lo que usted desee, especialmente teniendo en cuenta la cantidad de palabras que se utilizan una y otra vez, que no se tenga en cuenta la firma completa del método, etc.

En Ruby podría preguntar

object.respond_to? :sync

Entonces, sí, tiene un método llamado "sincronización", sea lo que sea que eso signifique.

En Objective-C podría preguntar algo similar, es decir, "¿se ve / camina / charla como algo que se sincroniza?":

[myObject respondsToSelector:@selector(sync)]

Incluso mejor, a costa de algo de verbosidad, puedo preguntar algo más específico, es decir, "¿se ve / camina / charla como algo que se sincroniza con MobileMe?":

[myObject respondsToSelector:@selector(sync:withMobileMeAccount:)]

Eso es pato escribiendo a nivel de especie.

Pero realmente preguntarle a un objeto si está prometiendo implementar la sincronización con MobileMe ...

[receiver conformsToProtocol:@protocol(MobileMeSynchronization)]

Por supuesto, podría implementar protocolos simplemente verificando la presencia de una serie de selectores que considere la definición de un protocolo / pato, y si son lo suficientemente específicos. ¿En qué punto el protocolo es solo una abreviación de un gran grupo de respuestas feas_to? consultas, y algún azúcar sintáctico muy útil para el compilador / IDE para usar.

Las interfaces / protocolos son otra dimensión de los metadatos de objetos que se pueden usar para implementar un comportamiento dinámico en el manejo de esos objetos. En Java, el compilador simplemente exige ese tipo de cosas para la invocación de método normal. Pero incluso los lenguajes dinámicos como Ruby, Python, Perl, etc. implementan una noción de tipo que va más allá de "a qué métodos responde un objeto". De ahí la palabra clave class. Javascript es el único lenguaje realmente utilizado sin ese concepto. Si tienes clases, las interfaces también tienen sentido.

Es ciertamente más útil para bibliotecas más complicadas o jerarquías de clases que en la mayoría de los códigos de aplicaciones, pero creo que el concepto es útil en cualquier idioma.

Además, alguien más mencionó mixins. Los mixins de Ruby son una forma de compartir código, por ejemplo, se relacionan con la implementación de una clase. Las interfaces / protocolos se refieren a la interfaz de una clase u objeto. En realidad, pueden complementarse entre sí. Puede tener una interfaz que especifique un comportamiento y una o más mezclas que ayuden a un objeto a implementar ese comportamiento.

Por supuesto, no puedo pensar en ningún idioma que realmente tenga las dos características distintivas del idioma de primera clase. En aquellos con mixins, incluir el mixin generalmente implica la interfaz que implementa.




Creo que el uso de las interfaces está más determinado por la cantidad de personas que usarán su biblioteca. Si solo eres tú o un equipo pequeño, la documentación y la convención estarán bien y requerir interfaces será un impedimento. Si se trata de una biblioteca pública, las interfaces son mucho más útiles porque obligan a las personas a proporcionar los métodos correctos en lugar de simplemente dar pistas. Así que las interfaces son definitivamente una característica valiosa para escribir bibliotecas públicas y supongo que la falta (o al menos el énfasis) es una de las muchas razones por las que los lenguajes dinámicos se utilizan más para las aplicaciones y los idiomas fuertemente tipados para las grandes bibliotecas.




Sí, hay un punto

Si no usa interfaces explícitamente, su código aún usa el objeto como si implementara ciertos métodos, simplemente no está claro cuál es la interfaz tácita.

Si define una función para aceptar una interfaz (en PHP decir) entonces fallará antes, y el problema será con la persona que llama, no con el método haciendo el trabajo. En general, fallar antes es una buena regla general a seguir.




como programador de PHP, como yo lo veo, una interfaz se usa básicamente como un contrato. Le permite decir que todo lo que utiliza esta interfaz DEBE implementar un conjunto determinado de funciones.

No sé si eso es tan útil, pero encontré un poco un obstáculo para tratar de entender de qué se trataban las interfaces.




En un lenguaje como PHP donde una llamada a método que no existe produce un error fatal y toma toda la aplicación hacia abajo, entonces las interfaces sí tienen sentido.

En un lenguaje como Python donde puede detectar y manejar llamadas a métodos no válidos, no es así.




René, lea mi respuesta a la pregunta "Mejores prácticas para arquitecturas de grandes sistemas en un lenguaje dinámico" aquí en . Discuto algunos beneficios de ceder la libertad de los lenguajes dinámicos para ahorrar esfuerzo de desarrollo y facilitar la introducción de nuevos programadores al proyecto. Las interfaces, cuando se usan correctamente, contribuyen en gran medida a escribir software confiable.




Es como decir que no necesitas tipos explícitos en un lenguaje de tipado dinámico. ¿Por qué no haces de todo un "var" y documentas sus tipos en otro lugar?

Es una restricción impuesta a un programador por un programador. Hace más difícil que te dispares en el pie; le da menos espacio para el error.




Bueno, sin duda sería más fácil verificar si un objeto dado admite una interfaz completa, en lugar de no bloquearse cuando llama al uno o dos métodos que utiliza en el método inicial, por ejemplo, para agregar un objeto a una lista interna.

El tipado en pato tiene algunos de los beneficios de las interfaces, es decir, fácil de usar en todas partes, pero el mecanismo de detección todavía falta.




Si creía que tenía que hacerlo, podría implementar un tipo de interfaz con una función que compare los métodos / atributos de un objeto con una firma determinada. Aquí hay un ejemplo muy básico:

file_interface = ('read', 'readline', 'seek')

class InterfaceException(Exception): pass

def implements_interface(obj, interface):
    d = dir(obj)
    for item in interface:
        if item not in d: raise InterfaceException("%s not implemented." % item)
    return True

>>> import StringIO
>>> s = StringIO.StringIO()
>>> implements_interface(s, file_interface)
True
>>> 
>>> fp = open('/tmp/123456.temp', 'a')    
>>> implements_interface(fp, file_interface)
True
>>> fp.close()
>>> 
>>> d = {}
>>> implements_interface(d, file_interface)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in implements_interface
__main__.InterfaceException: read not implemented.

Por supuesto, eso no garantiza mucho.




Además de las otras respuestas, solo quiero señalar que Javascript tiene una instancia de palabra clave que devolverá verdadero si la instancia dada está en alguna parte en la cadena de prototipos de un objeto dado.

Esto significa que si usa su "objeto de interfaz" en la cadena de prototipos para sus "objetos de implementación" (ambos son simplemente objetos para JS), entonces puede usar instanceof para determinar si lo "implementa". Esto no ayuda al aspecto de cumplimiento, pero sí ayuda en el aspecto de polimorfismo, que es un uso común para las interfaces.

MDN instanceof Reference




Deja de intentar escribir Java en un lenguaje dinámico.







Lo pienso más como un nivel de conveniencia. Si tiene una función que toma un objeto "similar a un archivo" y solo llama a un método de lectura (), entonces es inconveniente, incluso limitante, forzar al usuario a implementar algún tipo de interfaz de archivo. Es igual de fácil comprobar si el objeto tiene un método de lectura.

Pero si su función espera un gran conjunto de métodos, es más fácil verificar si el objeto admite una interfaz y luego verificar si admite cada método en particular.




En los lenguajes dinámicos puede usar valores de manera que sepa que son correctos. En un lenguaje estáticamente tipado, solo puede usar valores de forma que el compilador sepa que son correctos. Necesita todas las cosas que mencionó para recuperar la flexibilidad que le quita el sistema de tipos (no estoy atacando los sistemas de tipo estático, la flexibilidad a menudo se elimina por buenas razones). Esta es una gran complejidad que no tiene que tratar en un lenguaje dinámico si desea usar los valores de una manera que el diseñador de lenguaje no anticipó (por ejemplo, poner valores de diferentes tipos en una tabla hash).

Entonces no es que no puedas hacer estas cosas en un lenguaje estáticamente tipado (si tienes reflejo en el tiempo de ejecución), es simplemente más complicado.





php interface dynamic-languages duck-typing