2012-05-08 23 views
8

Estaba leyendo la documentación de Dart y estaba un poco confundido, tal vez porque vengo de Ruby, sobre cómo usar las interfaces. Por supuesto, las interfaces no son exclusivas de Dart y hay bastantes explicaciones sobre cuándo se debe usar una interfaz. This one, por ejemplo, parece estar diciendo que las interfaces solo son útiles cuando estás en un equipo. ¿Qué se supone que significa en el mundo del código abierto, donde todo el mundo lee y reutiliza el código de otra persona?Cuándo usar interfaces en Dart?

Una explicación interesante que he visto parecía estar dando a entender que se utilizan interfaces:

  1. en lenguas que carecen de la herencia múltiple, y
  2. para el caso de que alguna manera sirven como una solución para la falta de herencia múltiple

No entiendo eso. Entiendo que los módulos en Ruby son una solución porque me permiten definir métodos reales con cuerpos reales. Las interfaces solo me permiten definir qué métodos debe tener una clase que lo implementa. ¿Cuál es el truco? ¿Puede alguien hablar de un ejemplo realmente útil en el que pueda ver de inmediato el valor de usar interfaces?

P.S. En una nota relacionada, ¿hay alguna forma de usar herencia múltiple en Dart?

Respuesta

19

Las interfaces son útiles porque le permiten cambiar las implementaciones de una clase, al tiempo que permiten la validación de que el tipo que se está entregando cumple con los requisitos de la interfaz.

tomar el ejemplo siguiente (a menudo utilizado):

interface Quackable { 
    void quack(); 
} 

Esto define los requisitos de una clase que se pasarán a un método tal como:

sayQuack(Quackable quackable) { 
    quackable.quack(); 
} 

que le permite hacer uso de cualquier implementación de un objeto Quackable, como:

class MockDuck implements Quackable { 
    void quack() => print("quack"); 
} 

class EnterpriseDuck implements Quackable { 
    void quack() { 
    // connect to three enterprise "ponds" 
    // and eat some server bread 
    // and say "quack" using an messaging system 
    } 

} 

Ambas implementaciones funcionarán con la función sayQuack(), pero una requiere significativamente menos infraestructura que la otra.

sayQuack(new EnterpriseDuck()); 
sayQuack(new MockDuck()); 

que utilizan este patrón todo el tiempo en el mundo de Java, en la construcción de soluciones que hacen uso de un poco de "pato de la empresa". Al desarrollar localmente, todo lo que necesito es poder llamar a la función sayQuack() y devolver algunos datos falsos codificados.

pato escribir

Debido dardo se escribe opcionalmente, que en realidad no necesita usar la interfaz, sólo tiene que escribir una clase que contiene la firma del método correcto funcionará (aunque las herramientas no podrán para validarlo).

class Person { // note: no implements keyword 
    void quack() => "I'm not a duck"; 
} 

sayQuack(new Person()); // provides the quack method, so this will still work 

Todas las clases son interfaces

Por último, todas las clases son también las interfaces. Esto significa que, aunque un sistema de terceros se haya escrito sin utilizar interfaces, puede seguir utilizando una clase concreta como si fuera una interfaz.

Por ejemplo, imaginemos la siguiente biblioteca de la empresa:

class EnterpriseDuck { // note: no implements keyword 
    void quack() { 
    // snip 
    } 
} 

sayQuack(EnterpriseDuck duck) { // takes an instance of the EnterpriseDuck class 
    duck.quack(); 
} 

y desea pasar un pato simulacro en el método sayQuack de manera que el tipo de corrector puede validar. Usted puede crear su mockDuck para implementar la interfaz implicado por EnterpriseDuck, simplemente usando el EnterpriseDuck como una interfaz:

class MockDuck implements EnterpriseDuck { 
    void quack() => "I'm a mock enterprise duck"; 
} 

herencia múltiple

En términos de herencia múltiple, esto no es posible en Dart. Puede, sin embargo, implementar múltiples interfaces y ofrecer sus propias implementaciones de los métodos necesarios, por ejemplo:

class MultiDuck implements Quackable, EnterpriseDuck, Swimable { 
    // snip... 
} 

Las interfaces pueden tener clases predeterminadas

A medida que usa dardo, se encuentra que la mayoría de las clases" "en realidad son interfaces. List, String, etc ... son todas las interfaces con implementaciones predeterminadas. Cuando se llama a

List myList = new List(); 

en realidad está utilizando una interfaz de lista, y la nueva palabra clave redirige desde la interfaz a una aplicación lista por defecto subyacente.

lo que respecta a desarrollar en un equipo de

interfaces son útiles en el desarrollo del equipo, incluso en el mundo del código abierto. La interfaz define los métodos y las propiedades que debe construir para que su componente funcione con mi componente. Puedes construir tu propia implementación de prueba de esa interfaz, y puedo construir mi implementación concreta de esa interfaz, y cuando ambos terminemos, podemos integrarnos. Sin la interfaz publicada y compartida, necesitaría proporcionar mi implementación concreta antes de que realmente pueda comenzar.

Espero que ayude!

+2

Muchas gracias, Chris, eso era exactamente lo que necesitaba. Además, los nombres de tus clases en los ejemplos son adorables. – snitko

+0

en "piense", dos de los comentarios de su código: "// nota: ninguna palabra clave de interfaz" en lugar de "// nota: no implementa palabra clave". – GameAlchemist

+3

Considere actualizar esto o agregue un comentario a esta publicación explicando que la palabra clave de la interfaz ya no se usa en Dart. –

1

Las interfaces son parte del sistema de tipo en Dart y las declaraciones de tipo son opcionales. Esto significa que las interfaces son opcionales también.

Las interfaces le ayudan a documentar los métodos a los que responde su objeto. Si implementa la interfaz, se compromete a implementar todos los métodos en la interfaz.

Dart utiliza esta información para presentar advertencias en tiempo de compilación de tipos no coincidentes, para proporcionar sugerencias más útiles para la ayuda de código y para ayudar con algunas refactorizaciones.

+0

Claro, entiendo que son opcionales. Y no veo el valor de usarlos. Las advertencias de tiempo de compilación no parecen ser una gran ganancia. Sin embargo, admito que puedo estar fundamentalmente equivocado en mi evaluación. Es por eso que estaba buscando un ejemplo del mundo real que demuestre el valor del uso de interfaces. – snitko

4

Básicamente, las interfaces no tienen nada que ver con la herencia múltiple. Es posible falsificar múltiples interfaces de herencia y abuso al hacerlo, pero si quieres una verdadera herencia múltiple (o mixins o rasgos), entonces Dart no los proporciona (actualmente - creo que los mixins encontrarán su camino en algún día))

Para qué son buenas las interfaces es contrato explícito.Supongamos que tiene dos componentes A y B que deben funcionar entre sí. Seguramente puede llamar directamente al B desde A y funcionará, pero la próxima vez que desee cambiar B, tendrá que mirar A cómo lo está usando. Eso es porque B no expone una interfaz explícita. Sí, la palabra correcta para interfaces no es implementar pero exponer.

Si oculta la implementación de B detrás de una interfaz y sólo proporciona la interfaz a A, a continuación, puede cambiar a voluntad B y sólo preocuparse por sigue exponiendo la misma interfaz. La interfaz puede incluso ser expuesta por más de una clase, y la persona que llama no tiene que preocuparse (ni siquiera saber).

cuenta que la interfaz palabra tiene dos significados aquí: El general de contrato del componente, que también se puede describir de manera clara Inglés en la documentación, y un lenguaje especial construir que le ayuda a describir (y también aplicando) algunas partes del contrato dentro del lenguaje de programación.

No necesariamente tiene que usar la construcción del lenguaje, pero se considera un buen estilo para usarlo para describir las partes del contrato que el lenguaje de programación le permite.

Ahora, ¿qué diablos es un contrato aquí? En pocas palabras, contract es una descripción de lo que el componente espera de su usuario y lo que el usuario puede esperar del componente.

Por ejemplo, digamos que tengo un método que calcula el valor absoluto de un número:

class MathUtils { 
    /// Computes absolute value of given [number], which must be a [num]. 
    /// Return value is also a [num], which is never negative. 
    absoluteValue(number) { 
    ... here's the implementation ... 
    } 
} 

El contrato aquí está completamente descrito en el comentario de documentación (bueno, no del todo, se podría describir también qué valor absoluto es, pero esto es lo suficientemente bueno). Bueno ... pero algunas partes del comentario se pueden expresar directamente en el idioma, ¿verdad?

class MathUtils { 
    /// Computes absolute value of given [number]. 
    /// Return value is never negative. 
    num absoluteValue(num number) { 
    ... here's the implementation ... 
    } 
} 

Tenga en cuenta que algunas partes del contrato simplemente no pueden expresarse en el lenguaje de programación - aquí, el idioma no tiene idea de lo que valor absoluto Es decir, este necesita para mantenerse en el comentario. Además, no puede expresar que el valor de retorno nunca es negativo, por lo que también debe permanecer en el comentario. Pero, de hecho, los lectores del código saben lo que un valor absoluto es (y que nunca es negativo) y el nombre del método es bastante claro el propósito, por lo que el comentario puede ser completamente excluido:

class MathUtils { 
    num absoluteValue(num number) { 
    ... here's the implementation ... 
    } 
} 

Así que ahora, algunas partes del contrato se expresan explícitamente, utilizando los medios del lenguaje, y algunas partes se expresan implícitamente (usted confía en que la gente sepa qué valor absoluto es).

Y las interfaces en el idioma se utilizan para desacoplar el contrato de la implementación. Probablemente sea excesivo utilizarlo en programas pequeños, pero vale la pena cuando se hacen programas más grandes (que no tiene que involucrar el trabajo en equipo).

Uff, esto resultó ser más largo de lo que esperaba. Espero que ayude.