Pregunta

Interfaces Le permite 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.

clases abstractas le permite hacer lo mismo, además de agregar código al método.

Ahora bien, si se puede 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 desde C++ hasta Java, que es en lo que se basa la OO de PHP.¿Es el concepto útil en Java pero no en PHP?¿Es solo una forma de evitar que haya marcadores de posición en la clase abstracta?¿Me estoy perdiendo de algo?

¿Fue útil?

Solución

El objetivo de las interfaces es brindarle la flexibilidad de obligar a su clase a implementar múltiples interfaces, pero aún así no permitir la herencia múltiple.Los problemas con la herencia de múltiples clases son muchos y variados y el Wikipedia La página que aparece 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 hoy en día desactivan la herencia múltiple pero llaman a las interfaces de las clases base abstractas y permiten que una clase "implemente" tantas como quiera.

Otros consejos

El concepto es útil en todos los aspectos de la programación orientada a objetos.Para mí, considero una interfaz como un contrato.Siempre que mi clase y la suya estén de acuerdo con este contrato de firma de método, podemos "interconectarnos".En cuanto a las clases abstractas, las veo más como clases base que eliminan algunos métodos y necesito completar los detalles.

¿Por qué necesitarías una interfaz si ya existen clases abstractas?Para evitar la herencia múltiple (puede causar múltiples problemas conocidos).

Uno de esos problemas:

El "problema de diamantes" (a veces denominado el "diamante mortal de la muerte") es una ambigüedad que surge cuando dos clases B y C heredan de A y Clase D hereda de B y C.Si hay un método en A que B y C ha anulado, y D no lo anula, entonces qué versión del método heredan d:¿El de B o el de C?

Fuente: https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem

¿Por qué/cuándo utilizar una interfaz?Un ejemplo...Todos los coches del mundo tienen la misma interfaz (métodos)... AccelerationPedalIsOnTheRight(), BrakePedalISOnTheLeft().Imagínese que cada marca de automóvil tuviera estos "métodos" diferentes a los de otra marca.BMW tendría los frenos en el lado derecho y Honda tendría frenos en el lado izquierdo de la rueda.La gente tendría que aprender cómo funcionan estos "métodos" cada vez que compraran una marca diferente de automóvil.Por eso es una buena idea tener la misma interfaz en varios "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 los métodos que están en la interfaz).

// Methods inside this interface must be implemented in all classes which implement this interface.
interface IPersonService
{   
    public function Create($personObject);
}

class MySqlPerson implements IPersonService
{
    public function Create($personObject)
    {
        // Create a new person in MySql database.
    }
}

class MongoPerson implements IPersonService
{
    public function Create($personObject)
    {
        // Mongo database creates a new person differently then MySQL does. But the code outside of this method doesn't care how a person will be added to the database, all it has to know is that the method Create() has 1 parameter (the person object).
    }
}

De esta manera, el Create() El método siempre se utilizará de la misma manera.No importa si estamos usando el MySqlPerson clase o el MongoPerson clase.La forma en que utilizamos un método sigue siendo la misma (la interfaz sigue siendo la misma).

Por ejemplo, se usará así (en todas partes de nuestro código):

new MySqlPerson()->Create($personObject);
new MongoPerson()->Create($personObject);

De esta manera, algo como esto no puede suceder:

new MySqlPerson()->Create($personObject)
new MongoPerson()->Create($personsName, $personsAge);

Es mucho más fácil recordar una interfaz y usar la misma en todas partes que varias diferentes.

De esta manera, el interior del Create() El 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 debe saber es que el método Create() 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;sólo tiene que saber cómo usarlo/llamarlo.

También puedes hacer esto sin una interfaz, pero si usas una interfaz, es "más seguro" (porque evita que cometas 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 implementen la interfaz.De esta manera puede estar seguro de que CUALQUIER clase que implemente el IPersonService interfaz, tendrá el método Create() (en este ejemplo) y necesitará solo 1 parámetro ($personObject) para ser llamado/usado.

Una clase que implementa una interfaz debe implementar todos los métodos que la interfaz tiene o tiene.

Espero no haberme repetido demasiado.

Para mí, la diferencia entre usar una interfaz y una clase abstracta tiene más que ver con la organización del código que con la aplicación por parte del lenguaje mismo.Los uso mucho cuando preparo código para que otros desarrolladores trabajen con él para que se mantengan dentro de los patrones de diseño previstos.Las interfaces son una especie de "diseño por contrato" mediante el cual su código acepta responder a un conjunto prescrito de llamadas API que pueden provenir de un código al que no tiene acceso.

Si bien la herencia de una clase abstracta es una relación "es una", eso no siempre es lo que se desea, e implementar una interfaz es más bien una relación "actúa como una".Esta diferencia puede ser bastante significativa en ciertos contextos.

Por ejemplo, digamos que tiene una cuenta de clase abstracta desde la cual 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 incluirse en controladores que esperan utilizar esas API.Al controlador no le importa qué tipo de objeto sea

Por el contrario, también puedo crear un objeto que no se extienda desde Cuenta, digamos una clase abstracta de Usuario, y aun así implementar Listable y Editable, pero no Versionable, lo cual no tiene sentido aquí.

De esta manera, estoy diciendo que la subclase FooUser NO es una cuenta, pero SÍ actúa como un objeto editable.Asimismo, BarAccount se extiende desde Cuenta, pero no es una subclase de Usuario, sino que implementa Editable, Listable y también Versionable.

Agregar todas estas API para Editable, Listable y Versionable a las clases abstractas en sí no solo sería desordenado y feo, sino que duplicaría las interfaces comunes en Cuenta y Usuario, o forzaría a mi objeto Usuario a implementar Versionable, probablemente solo para lanzar un excepción.

Las interfaces son esencialmente un modelo de lo que puedes crear.Definen qué métodos una clase debe tener, pero puedes crear métodos adicionales fuera de esas limitaciones.

No estoy seguro de a qué te refieres con no poder agregar código a los métodos, porque puedes hacerlo.¿Está aplicando la interfaz a una clase abstracta o a la clase que la extiende?

Un método en la interfaz aplicado a la clase abstracta deberá implementarse 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 con tanta frecuencia 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 todo esté correcto.

Utilizarás interfaces en PHP:

  1. Para ocultar la implementación: establezca un protocolo de acceso a una clase de objetos y cambie la implementación subyacente sin refactorizar en todos los lugares donde haya usado esos objetos.
  2. Para verificar el tipo, como asegurarse de que un parámetro tenga un tipo específico $object instanceof MyInterface
  3. Para imponer la verificación de parámetros en tiempo de ejecución
  4. Para implementar múltiples comportamientos en una sola clase (construir tipos complejos)

    class Car implementa EngineInterface, BodyInterface, SteeringInterface {

para que un Car objeto ca ahora start(), stop() (Interfaz del motor) o goRight(),goLeft() (Interfaz de dirección)

y otras cosas en las que no puedo pensar ahora

El número 4 es probablemente el caso de uso más obvio que no se puede abordar con clases abstractas.

De Pensar en Java:

Una interfaz dice, “Así es como se verán todas las clases que implementan esta interfaz en particular.” Por lo tanto, cualquier código que utiliza una interfaz en particular sabe qué métodos se pueden llamar para esa interfaz, y eso es todo.Entonces la interfaz se utiliza para establecer un "protocolo" entre clases.

Las interfaces existen no como una base sobre la cual se pueden extender las clases, sino como un mapa de funciones requeridas.

El siguiente es un ejemplo del uso de una interfaz donde una clase abstracta no encaja:
Digamos que tengo una aplicación de calendario que permite a los usuarios importar datos de calendario desde 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 todas tengan los métodos públicos comunes que mi aplicación necesita para obtener los datos.

<?php

interface ImportableFeed 
{
    public function getEvents();
}

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 son necesarias para implementar la interfaz que permite que mi aplicación las consuma.Si tuviera que usar una clase abstracta, podría ignorar fácilmente el hecho de que no he anulado el método getEvents(), lo que interrumpiría mi aplicación en este caso, mientras que usar una interfaz no permitiría que mi aplicación se ejecutara si CUALQUIERA de los métodos definido en la interfaz no existe en la clase que lo implementó.A mi aplicación no le tiene que importar qué clase usa para obtener datos de un feed, solo que los métodos que necesita para obtener esos datos estén presentes.

Para llevar esto un paso más allá, la interfaz resulta extremadamente útil cuando vuelvo a mi aplicación de calendario con la intención de agregar otro tipo de feed.Usar la interfaz ImportableFeed significa que puedo continuar agregando más clases que importen diferentes tipos de feeds simplemente agregando nuevas clases que implementen esta interfaz.Esto me permite agregar toneladas de funcionalidad sin tener que agregar volumen innecesariamente a mi aplicación principal, ya que mi aplicación principal solo depende de que existan los métodos públicos disponibles que requiere la interfaz, siempre y cuando mis nuevas clases de importación de feeds implementen la interfaz ImportableFeed, entonces puedo Sé que puedo dejarlo en su lugar y seguir moviéndome.

Este es sólo un comienzo muy simple.Luego puedo crear otra interfaz que todas mis clases de calendario deban implementar y que ofrezca más funcionalidad específica para el tipo de fuente que maneja la clase.Otro buen ejemplo sería un método para verificar el tipo de alimento, etc.

Esto va más allá de la pregunta, pero como utilicé el ejemplo anterior:Las interfaces tienen sus propios problemas si se usan de esta manera.Me encuentro en la necesidad de asegurar que el resultado devuelto por los métodos implementados coincida con la interfaz y para lograr esto uso un IDE que lee bloques PHPDoc y agrego el tipo de retorno como una sugerencia de tipo en un bloque PHPDoc de la interfaz que luego traducir a la clase concreta que lo implementa.Mis clases que consumen la salida de datos de las clases que implementan esta interfaz sabrán al menos que esperan una matriz devuelta en este ejemplo:

<?php
interface ImportableFeed 
{
    /**
     * @return array
     */
    public function getEvents();
}

No hay mucho espacio para comparar clases e interfaces abstractas.Las interfaces son simplemente mapas que, cuando se implementan, requieren que la clase tenga un conjunto de interfaces públicas.

Las interfaces no sirven sólo para garantizar que los desarrolladores implementen ciertos métodos.La idea es que debido a que se garantiza que estas clases tendrán ciertos métodos, puedes usar estos métodos incluso si no conoces el tipo real de la clase.Ejemplo:

interface Readable {
  String read();
}

List<Readable> readables; // dunno what these actually are, but we know they have read();
for(Readable reader : readables)
  System.out.println(reader.read());

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 excepto algunos métodos.

Los lenguajes escritos dinámicamente tienen la noción de "escribir como pato" donde no se necesitan interfaces;eres libre de asumir que el objeto tiene el método al que estás invocando.Esto soluciona el problema en lenguajes escritos estáticamente donde su objeto tiene algún método (en mi ejemplo, read()), pero no implementa la interfaz.

En mi opinión, se deberían preferir las interfaces a las clases abstractas no funcionales.No me sorprendería que hubiera incluso un impacto en el rendimiento allí, ya que solo hay un objeto instanciado, en lugar de analizar dos y combinarlos (aunque no estoy seguro, no estoy familiarizado con el funcionamiento interno). de programación orientada a objetos PHP).

Es cierto que las interfaces son menos útiles/significativas que, por ejemplo, Java.Por otro lado, PHP6 introducirá aún más sugerencias de tipos, incluidas sugerencias de tipos para valores de retorno.Esto debería agregar algún valor a las interfaces PHP.

tl;dr:interfaces define una lista de métodos que deben seguirse (piense en API), mientras que una clase abstracta proporciona algunas funciones básicas/comunes, que las subclases perfeccionan según necesidades específicas.

No recuerdo si PHP es diferente a este respecto, pero en Java puedes implementar múltiples interfaces, pero no puedes heredar múltiples clases abstractas.Supongo que PHP funciona de la misma manera.

En PHP puedes aplicar múltiples interfaces separándolas con una coma (creo que no encuentro que sea una solución limpia).

En cuanto a múltiples clases abstractas, podría tener múltiples resúmenes que se extiendan entre sí (nuevamente, no estoy totalmente seguro de eso, pero creo que lo he visto en alguna parte antes).Lo único que no puedes extender es una clase final.

Las interfaces no mejorarán el rendimiento de su código ni nada por el estilo, pero pueden contribuir en gran medida a 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 usted 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 lugar de una clase.A veces quiero implementaciones de métodos predeterminados o variables que sean 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 tipos diferentes 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 prácticamente puedes enviar cualquier cosa a cualquier método, independientemente de su tipo.Puede escribir parámetros de método estáticamente, pero algunos de ellos están rotos (creo que String causa algunos contratiempos).Si a esto le sumamos el hecho de que no puedes escribir la mayoría de las otras referencias, no tiene mucho valor intentar forzar la escritura estática en PHP (en este punto).Y por eso, el valor de las interfaces en PHP, en este punto es mucho menor que en lenguajes más fuertemente tipados.Tienen el beneficio de la legibilidad, pero poco más.La implementación múltiple ni siquiera es beneficiosa, porque todavía hay que declarar los métodos y darles cuerpos dentro del implementador.

Las interfaces son como tus genes.

Las clases abstractas son como tus padres reales.

Sus propósitos son hereditarios, pero en el caso de clases abstractas versus interfaces, lo que se hereda es más específico.

A continuación se detallan los puntos para la interfaz PHP.

  1. Se utiliza para definir el número requerido de métodos en la clase [si desea cargar html, entonces se requiere ID y nombre, por lo que en este caso la interfaz incluye setID y setName].
  2. La interfaz fuerza estrictamente a la clase a incluir todos los métodos definidos en ella.
  3. Sólo puede definir el método en una interfaz con accesibilidad pública.
  4. También puede ampliar la interfaz como clase.Puede ampliar la interfaz en PHP usando la palabra clave extends.
  5. Ampliar múltiples interfaces.
  6. No puede implementar 2 interfaces si ambas comparten una función con el mismo nombre.Lanzará un error.

Código de ejemplo:

interface test{
    public function A($i);
    public function B($j = 20);
}

class xyz implements test{
    public function A($a){
        echo "CLASS A Value is ".$a;
    }
    public function B($b){
        echo "CLASS B Value is ".$b;
    }
}
$x = new xyz();
echo $x->A(11);
echo "<br/>";
echo $x->B(10);

Vimos que las clases e interfaces abstractas son similares en que proporcionan métodos abstractos que deben implementarse en las clases secundarias.Sin embargo, todavía tienen las siguientes diferencias:

1. Las interfaces pueden incluir constantes y métodos abstractos, pero no pueden contener variables y métodos concretos.

2.Todos los métodos en la interfaz deben estar en el público visibilidad alcance.

3. Una clase puede implementar más de un interfaz, mientras que puede heredar de una sola clase abstracta.

                                  interface                      abstract class
the code                     - abstract methods               - abstract methods
                             - constants                      - constants                  
                                                              - concrete methods
                                                              - concrete variables

access modifiers             
                             - public                         - public
                                                              - protected
                                                              - private
                                                                etc.
number of parents          The same class can implement
                           more than 1 interface              The child class can 
                                                              inherit only from 1 abstract class

¡Espero que esto ayude a cualquiera a entenderlo!

No sé sobre otros idiomas, cuál es el concepto de interfaz allí.Pero para PHP, haré todo lo posible para explicarlo.Solo tenga paciencia y comente si esto ayudó.

Una interfaz funciona como un "contrato", especificando qué hace un conjunto de subclases, pero no cómo lo hacen.

La regla

  1. No se puede crear una instancia de una interfaz.

  2. No puede implementar ningún método en una interfaz, es decir.solo contiene la firma del método pero no los detalles (cuerpo).

  3. Las interfaces pueden contener métodos y/o constantes, pero no atributos.Las constantes de interfaz tienen las mismas restricciones que las constantes de clase.Los métodos de interfaz son implícitamente abstractos.

  4. Las interfaces no deben declarar constructores o destructores, ya que estos son detalles de implementación de la clase nivel.
  5. Todos los métodos de una interfaz deben tener visibilidad pública.

Ahora tomemos un ejemplo.Supongamos que tenemos dos juguetes:uno es un perro y el 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 damos al usuario un control remoto que tiene un botón para hablar.

Cuando el usuario presiona el botón de hablar, el juguete tiene que hablar, sin importar si es un perro o un gato.

Este es un buen caso para usar una interfaz, no una clase abstracta porque las implementaciones son diferentes.¿Por qué?Recordar

Si necesita respaldar las clases secundarias agregando algún método no abstracto, debe usar clases abstractas.De lo contrario, las interfaces serían tu elección.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top