“Progtwig a una interfaz”. Qué significa eso?

Posible duplicado:
¿Qué significa “progtwigr en una interfaz”?

Sigo encontrándome con este término:

Progtwig a una interfaz.

¿Qué significa exactamente? Un escenario de diseño de la vida real sería muy apreciado.

Para decirlo simplemente, en lugar de escribir sus clases de una manera que dice

Depende de esta clase específica para hacer mi trabajo

lo escribes de una manera que dice

Depende de cualquier clase que haga estas cosas para hacer mi trabajo.

El primer ejemplo representa una clase que depende de una implementación concreta específica para hacer su trabajo. Inherentemente, eso no es muy flexible.

El segundo ejemplo representa una clase escrita en una interfaz . No le importa qué objeto concreto use, solo le preocupa que implemente cierto comportamiento. Esto hace que la clase sea mucho más flexible, ya que se puede proporcionar con cualquier cantidad de implementaciones concretas para hacer su trabajo.

Como ejemplo, una clase particular puede necesitar realizar algún registro. Si escribe la clase para que dependa de un TextFileLogger, la clase se verá forzada a escribir sus registros en un archivo de texto. Si desea cambiar el comportamiento del registro, debe cambiar la clase en sí. La clase está estrechamente unida con su registrador.

Sin embargo, si escribe la clase para que dependa de una interfaz ILogger y luego le proporciona a la clase un TextFileLogger, habrá logrado lo mismo, pero con el beneficio adicional de ser mucho más flexible. Puede proporcionar cualquier otro tipo de ILogger a voluntad, sin cambiar la clase. La clase y su registrador ahora están débilmente acoplados, y su clase es mucho más flexible.

Una interfaz es una colección de métodos relacionados, que solo contiene las firmas de esos métodos, no la implementación real.
Si una clase implementa una interfaz (la class Car implements IDrivable ) tiene que proporcionar un código para todas las firmas definidas en la interfaz.

Ejemplo básico:
Tienes que clases Coche y Bicicleta. Ambos implementan la interfaz IDrivable:

 interface IDrivable { void accelerate(); void brake(); } 

 class Car implements IDrivable { void accelerate() { System.out.println("Vroom"); } void brake() { System.out.println("Queeeeek");} } 

 class Bike implements IDrivable { void accelerate() { System.out.println("Rattle, Rattle, ..."); } void brake() { System.out.println("..."); } } 

Ahora supongamos que tienes una colección de objetos, que son todos “manejables” (todas sus clases implementan IDrivable):

 List vehicleList = new ArrayList(); list.add(new Car()); list.add(new Car()); list.add(new Bike()); list.add(new Car()); list.add(new Bike()); list.add(new Bike()); 

Si ahora desea recorrer esa colección, puede confiar en el hecho de que cada objeto de esa colección implementa accelerate() :

 for(IDrivable vehicle: vehicleList) { vehicle.accelerate(); //this could be a bike or a car, or anything that implements IDrivable } 

Al llamar a ese método de interfaz no está progtwigndo para una implementación, sino para una interfaz, un contrato que garantiza que el objective de la llamada implementa una determinada funcionalidad.
El mismo comportamiento se puede lograr utilizando la herencia, pero derivar de una clase base común da como resultado un acoplamiento estricto que se puede evitar utilizando interfaces.

El polymorphism depende de la progtwigción de una interfaz, no de una implementación.

La manipulación de objetos tiene dos ventajas únicamente en términos de la interfaz definida por las clases abstractas:

  1. Los clientes no son conscientes de los tipos específicos de objetos que utilizan, siempre y cuando los objetos se adhieran a la interfaz que esperan los clientes.
  2. Los clientes desconocen las clases que implementan estos objetos. Los clientes solo conocen la (s) clase (s) abstracta (s) que definen la interfaz.

Esto reduce en gran medida las dependencias de implementación entre subsistemas que conduce a este principio de progtwigción a una interfaz.

Vea el patrón de Método de fábrica para un mayor razonamiento de este diseño.

Fuente: ” Patrones de diseño: elementos del software reutilizable orientado a objetos ” por GOF

Ver también: Patrón de fábrica. Cuándo usar los métodos de fábrica?

Ejemplos del mundo real son en abundancia. Uno de ellos:

Para JDBC, está utilizando la interfaz java.sql.Connection . Sin embargo, cada controlador JDBC proporciona su propia implementación de Connection . No es necesario que sepa nada sobre la implementación particular, ya que se ajusta a la interfaz de Connection .

Otro es del marco de colecciones de Java. Hay una interfaz java.util.Collection , que define el size , add y remove métodos (entre muchos otros). Entonces puedes usar todos los tipos de colecciones de manera intercambiable . Digamos que tienes lo siguiente:

 public float calculateCoefficient(Collection collection) { return collection.size() * something / somethingElse; } 

Y otros dos métodos que invocan este. Uno de los otros métodos usa LinkedList porque es más eficiente para sus propósitos y el otro usa un TreeSet .

Debido a que LinkedList y TreeSet implementan la interfaz Collection , puede usar solo un método para realizar el cálculo del coeficiente. No es necesario duplicar tu código.

Y aquí viene el “progtwig a una interfaz”: no importa cómo se implemente exactamente el método size() , usted sabe que debería devolver el tamaño de la colección, es decir, que ha progtwigdo la interfaz Collection , en lugar de LinkedList y TreeSet en particular.

Pero mi consejo es encontrar una lectura, tal vez un libro (“Pensando en Java”, por ejemplo), donde se explica el concepto en detalle.

Cada objeto tiene una interfaz expuesta. Una colección tiene Add , Remove , At , etc. Un socket puede tener Send , Receive , Close , etc.

Todos los objetos a los que se puede hacer referencia tienen una implementación concreta de estas interfaces.

Ambas cosas son obvias, sin embargo, lo que es algo menos obvio …

Su código no debe basarse en los detalles de implementación de un objeto, solo su interfaz publicada.

Si lo llevas al extremo, solo codificarías contra Collection y demás (en lugar de ArrayList ). Más prácticamente, solo asegúrate de cambiar algo conceptualmente idéntico sin romper tu código.

Para sacar el ejemplo de Collection : tienes una colección de algo, en realidad estás usando ArrayList porque por qué no . Debes asegurarte de que tu código no se va a romper si, por ejemplo, terminas usando LinkedList en el futuro.

Básicamente, significa que la única parte de la biblioteca en la que va a utilizar debe confiar en su API (interfaz de progtwigción de aplicaciones) y que no debe basar su aplicación en la implementación concreta de la biblioteca.

p.ej. Supone que tienes una biblioteca que te da una stack . La clase te da un par de métodos. Digamos push , pop , isempty y top . Debe escribir su aplicación confiando solo en esto. Una forma de violar esto sería echar un vistazo al interior y descubrir que la stack se implementa utilizando una matriz de algún tipo, de modo que si extrae de una stack vacía, obtendría algún tipo de excepción de índice y luego captaría esto en lugar de confiar en el método isempty que proporciona la clase. El primer enfoque fallaría si el proveedor de la biblioteca pasara de usar una matriz a usar algún tipo de lista, mientras que la última seguiría funcionando suponiendo que el proveedor mantuviera su API funcionando.

La “Progtwigción a una interfaz” ocurre cuando usa bibliotecas, otro código del que depende en su propio código. Entonces, la forma en que otro código se representa para usted, los nombres del método, sus parámetros, valores de retorno, etc. conforman la interfaz a la que tiene que progtwigr. Entonces se trata de cómo usar código de terceros.

También significa que no tiene que preocuparse por las partes internas del código del que depende, siempre que la interfaz se mantenga igual, su código es seguro (bueno, más o menos …)

Técnicamente hay detalles más finos, como conceptos de lenguaje llamados “interfaces” en Java, por ejemplo.

Si desea obtener más información, puede preguntar qué significa “Implementar una interfaz” …

Creo que este es uno de los mantras de Erich Gamma. No puedo encontrar la primera vez que lo describió (antes del libro de GOF), pero puede verlo discutido en una entrevista en: http://www.artima.com/lejava/articles/designprinciples.html