Las interfaces le permiten crear código que define los métodos de las clases que lo implementan. Sin embargo, no puede agregar ningún código a esos métodos.
Las clases abstractas le permiten hacer lo mismo, junto con agregar código al método.
Ahora, si puedes lograr el mismo objetivo con clases abstractas, ¿por qué necesitamos el concepto de interfaces?
Me han dicho que tiene que ver con la teoría OO de C ++ a Java, que es en lo que se basa el material OO de PHP. ¿El concepto es útil en Java pero no en PHP? ¿Es solo una forma de evitar tener marcadores de posición en la clase abstracta? ¿Me estoy perdiendo de algo?
Respuestas:
El objetivo de las interfaces es darle la flexibilidad de obligar a su clase a implementar múltiples interfaces, pero no permitir la herencia múltiple. Los problemas con la herencia de múltiples clases son muchos y variados y la página de Wikipedia en él los resume bastante bien.
Las interfaces son un compromiso. La mayoría de los problemas con la herencia múltiple no se aplican a las clases base abstractas, por lo que la mayoría de los lenguajes modernos actualmente deshabilitan la herencia múltiple pero llaman a las interfaces de las clases base abstractas y permiten que una clase "implemente" todas las que quieran.
fuente
El concepto es útil en la programación orientada a objetos. Para mí, pienso en una interfaz como un contrato. Mientras mi clase y su clase estén de acuerdo con este método de firma de contrato, podemos "interactuar". En cuanto a las clases abstractas, las veo como más clases básicas que resuelven algunos métodos y necesito completar los detalles.
fuente
¿Por qué necesitarías una interfaz, si ya hay clases abstractas? Para evitar la herencia múltiple (puede causar múltiples problemas conocidos).
Uno de esos problemas:
Fuente: https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem
¿Por qué / cuándo usar una interfaz? Un ejemplo ... Todos los autos en el mundo tienen la misma interfaz (métodos) ...
AccelerationPedalIsOnTheRight()
,BrakePedalISOnTheLeft()
. Imagine que cada marca de automóvil tendría estos "métodos" diferentes de otra marca. BMW tendría los frenos en el lado derecho, y Honda tendría frenos en el lado izquierdo del volante. Las personas tendrían que aprender cómo funcionan estos "métodos" cada vez que comprarían una marca de automóviles diferente. Por eso es una buena idea tener la misma interfaz en múltiples "lugares".¿Qué hace una interfaz por usted (por qué alguien usaría una)? Una interfaz le impide cometer "errores" (le asegura que todas las clases que implementan una interfaz específica tendrán todos los métodos que están en la interfaz).
De esta manera, el
Create()
método siempre se utilizará de la misma manera. No importa si estamos usando laMySqlPerson
clase o laMongoPerson
clase. La forma en que estamos utilizando un método permanece igual (la interfaz sigue siendo la misma).Por ejemplo, se usará así (en todas partes en nuestro código):
De esta manera, algo como esto no puede suceder:
Es mucho más fácil recordar una interfaz y usar la misma en todas partes, que múltiples diferentes.
De esta manera, el interior del
Create()
método puede ser diferente para diferentes clases, sin afectar el código "externo", que llama a este método. Todo lo que el código externo tiene que saber es que el métodoCreate()
tiene 1 parámetro ($personObject
), porque así es como el código externo usará / llamará al método. Al código externo no le importa lo que sucede dentro del método; solo tiene que saber cómo usarlo / llamarlo.También puede hacer esto sin una interfaz, pero si usa una interfaz, es "más segura" (porque evita que cometa errores). La interfaz le asegura que el método
Create()
tendrá la misma firma (los mismos tipos y el mismo número de parámetros) en todas las clases que implementan la interfaz. De esta manera, puede estar seguro de que CUALQUIER clase que implemente laIPersonService
interfaz tendrá el métodoCreate()
(en este ejemplo) y solo necesitará 1 parámetro ($personObject
) para ser llamado / utilizado.Una clase que implementa una interfaz debe implementar todos los métodos, que la interfaz hace / tiene.
Espero no haberme repetido demasiado.
fuente
La diferencia entre usar una interfaz y una clase abstracta tiene más que ver con la organización del código para mí que con la aplicación del lenguaje en sí. Los uso mucho cuando preparo código para que otros desarrolladores trabajen para que se mantengan dentro de los patrones de diseño previstos. Las interfaces son un tipo de "diseño por contrato" por el cual su código acepta responder a un conjunto prescrito de llamadas API que pueden provenir de un código que no tiene acceso.
Si bien la herencia de la clase abstracta es una relación "es un", eso no siempre es lo que desea, e implementar una interfaz es más una relación "actúa como una". Esta diferencia puede ser bastante significativa en ciertos contextos.
Por ejemplo, supongamos que tiene una cuenta de clase abstracta desde la que se extienden muchas otras clases (tipos de cuentas, etc.). Tiene un conjunto particular de métodos que solo son aplicables a ese grupo de tipos. Sin embargo, algunas de estas subclases de cuentas implementan Versionable, Listable o Editable para que puedan ser lanzadas a controladores que esperan usar esas API. Al controlador no le importa qué tipo de objeto es
Por el contrario, también puedo crear un objeto que no se extienda desde la Cuenta, digamos una clase abstracta de Usuario, y aún implementar Listable y Editable, pero no Versátil, lo que no tiene sentido aquí.
De esta manera, estoy diciendo que la subclase de FooUser NO es una cuenta, pero sí actúa como un objeto editable. Del mismo modo, BarAccount se extiende desde la Cuenta, pero no es una subclase de Usuario, sino que implementa Editable, Listable y Versionable.
Agregar todas estas API para Editable, Listable y Versionable en las clases abstractas en sí mismas no solo sería desordenado y feo, sino que duplicaría las interfaces comunes en Account and User, o forzaría a mi objeto User a implementar Versionable, probablemente solo para lanzar un excepción.
fuente
Las interfaces son esencialmente un plan para lo que puede crear. Definen qué métodos debe tener una clase , pero puede crear métodos adicionales fuera de esas limitaciones.
No estoy seguro de lo que quieres decir con no poder agregar código a los métodos, porque puedes hacerlo. ¿Estás aplicando la interfaz a una clase abstracta o la clase que la extiende?
Será necesario implementar un método en la interfaz aplicada a la clase abstracta en esa clase abstracta. Sin embargo, aplique esa interfaz a la clase extendida y el método solo necesita implementarse en la clase extendida. Podría estar equivocado aquí: no uso interfaces tan a menudo como podría / debería.
Siempre he pensado en las interfaces como un patrón para desarrolladores externos o un conjunto de reglas adicional para garantizar que las cosas sean correctas.
fuente
Utilizará interfaces en PHP:
$object instanceof MyInterface
Car
objeto pueda ahorastart()
,stop()
(EngineInterface) ogoRight()
,goLeft()
(Interfaz de dirección)y otras cosas que no puedo pensar en este momento
Número 4 es probablemente el caso de uso más obvio que no puede abordar con clases abstractas.
De Pensar en Java:
fuente
Las interfaces existen no como una base sobre la cual las clases pueden extenderse sino como un mapa de funciones requeridas.
El siguiente es un ejemplo de uso de una interfaz donde una clase abstracta no cabe:
Digamos que tengo una aplicación de calendario que permite a los usuarios importar datos de calendario de fuentes externas. Escribiría clases para manejar la importación de cada tipo de fuente de datos (ical, rss, atom, json) Cada una de esas clases implementaría una interfaz común que garantizaría que todos tengan los métodos públicos comunes que mi aplicación necesita para obtener los datos.
Luego, cuando un usuario agrega un nuevo feed, puedo identificar el tipo de feed que es y usar la clase desarrollada para ese tipo para importar los datos. Cada clase escrita para importar datos para un feed específico tendría un código completamente diferente, de lo contrario puede haber muy pocas similitudes entre las clases, aparte del hecho de que están obligados a implementar la interfaz que permite que mi aplicación los consuma. Si tuviera que usar una clase abstracta, podría ignorar fácilmente el hecho de que no he anulado el método getEvents () que luego rompería mi aplicación en este caso, mientras que usar una interfaz no permitiría que mi aplicación se ejecute si CUALQUIERA de los métodos definido en la interfaz no existe en la clase que lo implementó. Mi aplicación no tiene que preocuparse de qué clase usa para obtener datos de un feed,
Para llevar esto un paso más allá, la interfaz demuestra ser extremadamente útil cuando vuelvo a mi aplicación de calendario con la intención de agregar otro tipo de feed. El uso de la interfaz ImportableFeed significa que puedo continuar agregando más clases que importen diferentes tipos de feed simplemente agregando nuevas clases que implementen esta interfaz. Esto me permite agregar toneladas de funcionalidad sin tener que agregar un volumen innecesario a mi aplicación principal, ya que mi aplicación principal solo se basa en que existan los métodos públicos disponibles que la interfaz requiere, siempre que mis nuevas clases de importación de feeds implementen la interfaz ImportableFeed. Sé que puedo dejarlo en su lugar y seguir moviéndome.
Este es solo un comienzo muy simple. Luego puedo crear otra interfaz que se requiera que implementen todas mis clases de calendario que ofrezca más funcionalidad específica para el tipo de feed que maneja la clase. Otro buen ejemplo sería un método para verificar el tipo de alimentación, etc.
Esto va más allá de la pregunta, pero dado que utilicé el ejemplo anterior: las interfaces vienen con su propio conjunto de problemas si se usan de esta manera. Creo que necesito asegurar la salida que se devuelve de los métodos implementados para que coincida con la interfaz y para lograr esto, uso un IDE que lee bloques PHPDoc y agrego el tipo de retorno como una pista de tipo en un bloque PHPDoc de la interfaz que luego traducir a la clase concreta que lo implementa. Mis clases que consuman la salida de datos de las clases que implementan esta interfaz sabrán, al menos, que espera una matriz devuelta en este ejemplo:
No hay mucho espacio para comparar clases abstractas e interfaces. Las interfaces son simplemente mapas que, cuando se implementan, requieren que la clase tenga un conjunto de interfaces públicas.
fuente
Las interfaces no son solo para asegurarse de que los desarrolladores implementen ciertos métodos. La idea es que debido a que estas clases tienen ciertos métodos garantizados, puede usar estos métodos incluso si no conoce el tipo real de la clase. Ejemplo:
En muchos casos, no tiene sentido proporcionar una clase base, abstracta o no, porque las implementaciones varían enormemente y no comparten nada en común además de algunos métodos.
Los lenguajes escritos dinámicamente tienen la noción de "tipear patos" donde no se necesitan interfaces; puede suponer que el objeto tiene el método que está solicitando. Esto soluciona el problema en lenguajes estáticamente escritos donde su objeto tiene algún método (en mi ejemplo, read ()), pero no implementa la interfaz.
fuente
En mi opinión, las interfaces deberían preferirse a las clases abstractas no funcionales. No me sorprendería si hubiera incluso un golpe de rendimiento allí, ya que solo hay un objeto instanciado, en lugar de analizar dos, combinándolos (aunque, no estoy seguro, no estoy familiarizado con el funcionamiento interno de OOP PHP).
Es cierto que las interfaces son menos útiles / significativas que en comparación con, por ejemplo, Java. Por otro lado, PHP6 introducirá aún más sugerencias de tipo, incluida la sugerencia de tipo para los valores de retorno. Esto debería agregar algo de valor a las interfaces PHP.
tl; dr: interfaces define una lista de métodos que deben seguirse (piense en la API), mientras que una clase abstracta proporciona algunas funciones básicas / comunes, que las subclases refinan para necesidades específicas.
fuente
En PHP, puede aplicar varias interfaces separándolas con una coma (creo que no encuentro una solución limpia).
En cuanto a las múltiples clases abstractas, podría tener varios resúmenes que se extiendan entre sí (nuevamente, no estoy totalmente seguro de eso, pero creo que lo he visto en algún lugar antes). Lo único que no puedes extender es una clase final.
fuente
Las interfaces no le darán a su código ningún aumento en el rendimiento ni nada de eso, pero pueden hacer mucho para que sea mantenible. Es cierto que se puede usar una clase abstracta (o incluso una clase no abstracta) para establecer una interfaz para su código, pero las interfaces adecuadas (las que define con la palabra clave y que solo contienen firmas de métodos) son simplemente más fáciles de usar. ordenar y leer.
Dicho esto, tiendo a usar la discreción al decidir si usar o no una interfaz en una clase. A veces quiero implementaciones de métodos por defecto, o variables que serán comunes a todas las subclases.
Por supuesto, el punto sobre la implementación de múltiples interfaces también es sólido. Si tiene una clase que implementa múltiples interfaces, puede usar un objeto de esa clase como diferentes tipos en la misma aplicación.
Sin embargo, el hecho de que su pregunta sea sobre PHP hace que las cosas sean un poco más interesantes. Escribir en interfaces todavía no es increíblemente necesario en PHP, donde puedes alimentar prácticamente cualquier cosa a cualquier método, independientemente de su tipo. Puede escribir parámetros de método de forma estática, pero parte de eso está roto (String, creo, causa algunos problemas). Combine esto con el hecho de que no puede escribir la mayoría de las otras referencias, y no hay mucho valor en tratar de forzar la escritura estática en PHP ( en este punto ). Y debido a eso, el valor de las interfaces en PHP , en este puntoes mucho menos de lo que está en los idiomas más fuertemente tipados. Tienen el beneficio de la legibilidad, pero poco más. La implementación múltiple ni siquiera es beneficiosa, porque aún tiene que declarar los métodos y darles cuerpos dentro del implementador.
fuente
Debajo están los puntos para la interfaz PHP
Código de ejemplo:
fuente
Vimos que las clases abstractas y las interfaces son similares en el sentido de que proporcionan métodos abstractos que deben implementarse en las clases secundarias. Sin embargo, todavía tienen las siguientes diferencias:
Espero que esto ayude a cualquiera a entender!
fuente
Las interfaces son como tus genes.
Las clases abstractas son como tus padres reales.
Sus propósitos son hereditarios, pero en el caso de las clases abstractas frente a las interfaces, lo que se hereda es más específico.
fuente
No sé sobre otros idiomas, cuál es el concepto de interfaz allí. Pero para PHP, haré todo lo posible para explicarlo. Solo sea paciente y comente si esto ayudó.
La regla
Ahora tomemos un ejemplo. Supongamos que tenemos dos juguetes: uno es un perro y otro es un gato.
Como sabemos, un perro ladra y un gato maúlla. Estos dos tienen el mismo método de habla, pero con diferente funcionalidad o implementación. Supongamos que le estamos dando al usuario un control remoto que tiene un botón para hablar.
Este es un buen caso para usar una interfaz, no una clase abstracta porque las implementaciones son diferentes. ¿Por qué? Recuerda
Si necesita admitir las clases secundarias agregando algún método no abstracto, debe usar clases abstractas. De lo contrario, las interfaces serían su elección.
fuente