¿Qué significa “progtwigr en una interfaz”?

He visto esto mencionado algunas veces y no tengo claro lo que significa. ¿Cuándo y por qué harías esto?

Sé lo que hacen las interfaces, pero el hecho de que no tengo claro esto me hace pensar que me estoy perdiendo de usarlas correctamente.

¿Es así si lo hicieras?

IInterface classRef = new ObjectWhatever() 

Podrías usar cualquier clase que implemente IInterface ? ¿Cuándo necesitarías hacer eso? Lo único que se me ocurre es que si tienes un método y no estás seguro de qué objeto se pasará, espera que se implemente IInterface . No puedo pensar con qué frecuencia necesitarías hacer eso … (Además, ¿cómo podrías escribir un método que incluya un objeto que implemente una interfaz? ¿Es posible?)

Lo siento si me perdí completamente el punto.

Aquí hay algunas respuestas maravillosas a estas preguntas que entran en todo tipo de detalles sobre las interfaces y el código de acoplamiento flexible, inversión de control, etc. Hay algunas discusiones bastante embriagadoras, por lo que me gustaría aprovechar la oportunidad para analizar un poco las cosas para comprender por qué una interfaz es útil.

Cuando comencé a exponerme a las interfaces, yo también estaba confundido acerca de su relevancia. No entendí por qué los necesitabas. Si estamos usando un lenguaje como Java o C #, ya tenemos herencia y veo las interfaces como una forma más débil de herencia y pensamiento, “¿para qué molestarse?” En cierto sentido tenía razón, se puede pensar en las interfaces como una especie de herencia débil, pero más allá de eso, finalmente entendí su uso como una construcción del lenguaje al pensar en ellas como un medio para clasificar los rasgos o comportamientos comunes que fueron exhibidos por potencialmente muchas clases de objetos no relacionados.

Por ejemplo, supongamos que tiene un juego SIM y tiene las siguientes clases:

  class HouseFly inherits Insect { void FlyAroundYourHead(){} void LandOnThings(){} } class Telemarketer inherits Person { void CallDuringDinner(){} void ContinueTalkingWhenYouSayNo(){} } 

Claramente, estos dos objetos no tienen nada en común en términos de herencia directa. Pero, podrías decir que ambos son molestos.

Digamos que nuestro juego necesita tener algo aleatorio que moleste al jugador cuando cenan. Esto podría ser un HouseFly o un Telemarketer o ambos, pero ¿cómo permite ambos con una sola función? ¿Y cómo le pides a cada tipo de objeto diferente que “haga su cosa molesta” de la misma manera?

La clave para darse cuenta es que tanto un Telemarketer como HouseFly comparten un comportamiento común sin interpretación aunque no se parezcan en términos de modelarlos. Entonces, hagamos una interfaz que ambos puedan implementar:

  interface IPest { void BeAnnoying(); } class HouseFly inherits Insect implements IPest { void FlyAroundYourHead(){} void LandOnThings(){} void BeAnnoying() { FlyAroundYourHead(); LandOnThings(); } } class Telemarketer inherits Person implements IPest { void CallDuringDinner(){} void ContinueTalkingWhenYouSayNo(){} void BeAnnoying() { CallDuringDinner(); ContinueTalkingWhenYouSayNo(); } } 

Ahora tenemos dos clases que pueden ser molestas a su manera. Y no necesitan derivar de la misma clase base y compartir características inherentes comunes, simplemente necesitan cumplir el contrato de IPest , ese contrato es simple. Solo tienes que ser BeAnnoying . En este sentido, podemos modelar lo siguiente:

  class DiningRoom { DiningRoom(Person[] diningPeople, IPest[] pests) { ... } void ServeDinner() { when diningPeople are eating, foreach pest in pests pest.BeAnnoying(); } } 

Aquí tenemos un comedor que acepta varios comensales y varias plagas, tenga en cuenta el uso de la interfaz. Esto significa que en nuestro pequeño mundo, un miembro del conjunto de pests podría ser un objeto de Telemarketer o un objeto HouseFly .

El método ServeDinner se llama cuando se sirve la cena y se supone que nuestra gente en el comedor debe comer. En nuestro pequeño juego, es cuando nuestras plagas hacen su trabajo: se instruye a cada plaga para que sea molesta a través de la interfaz IPest . De esta forma, podemos hacer que tanto Telemarketers como HouseFlys sean molestos en cada una de sus formas: solo nos importa que tengamos algo en el objeto DiningRoom que sea una plaga, realmente no nos importa lo que sea y podrían no tienen nada en común con los demás.

Este ejemplo de pseudocódigo muy artificial (que se prolongó mucho más de lo que esperaba) simplemente pretende ilustrar el tipo de cosas que finalmente me iluminaron en términos de cuándo podríamos usar una interfaz. Me disculpo de antemano por la tontería del ejemplo, pero espero que ayude en su comprensión. Y, para estar seguro, las otras respuestas publicadas que ha recibido aquí realmente abarcan toda la gama del uso de las interfaces hoy en día en los patrones de diseño y las metodologías de desarrollo.

El ejemplo específico que solía dar a los estudiantes es que deben escribir

 List myList = new ArrayList(); // programming to the List interface 

en lugar de

 ArrayList myList = new ArrayList(); // this is bad 

Estos se ven exactamente iguales en un progtwig corto, pero si continúa usando myList 100 veces en su progtwig, puede comenzar a notar la diferencia. La primera statement garantiza que solo llame a los métodos en myList que están definidos por la interfaz List (por lo que no hay métodos específicos de ArrayList ). Si ha progtwigdo la interfaz de esta manera, más adelante puede decidir que realmente necesita

 List myList = new TreeList(); 

y solo tienes que cambiar tu código en ese punto. Ya sabes que el rest de tu código no hace nada que se rompa al cambiar la implementación porque has progtwigdo en la interfaz .

Los beneficios son aún más obvios (creo) cuando se habla de parámetros de método y valores devueltos. Toma esto por ejemplo:

 public ArrayList doSomething(HashMap map); 

Esa statement de método lo vincula a dos implementaciones concretas ( ArrayList y HashMap ). Tan pronto como se llame a ese método desde otro código, cualquier cambio en esos tipos probablemente signifique que también tendrá que cambiar el código de llamada. Sería mejor progtwigr a las interfaces.

 public List doSomething(Map map); 

Ahora no importa qué tipo de List devuelva, o qué tipo de Map se pasa como parámetro. Los cambios que realice dentro del método doSomething no lo doSomething a cambiar el código de llamada.

La progtwigción en una interfaz dice: “Necesito esta funcionalidad y no me importa de dónde viene”.

Considere (en Java) la List interfaces frente a las clases concretas ArrayList y LinkedList . Si todo lo que me importa es que tengo una estructura de datos que contiene múltiples elementos de datos a los que debería acceder mediante iteración, escogería una List (y eso es el 99% del tiempo). Si sé que necesito insertar / eliminar a tiempo constante de cualquier extremo de la lista, podría elegir la implementación concreta de LinkedList (o más probablemente, usar la interfaz Queue ). Si sé que necesito acceso aleatorio por índice, escogería la clase ArrayList concreto.

El uso de interfaces es un factor clave para hacer que su código sea fácilmente comprobable además de eliminar los acoplamientos innecesarios entre sus clases. Al crear una interfaz que define las operaciones en su clase, permite que las clases que desean usar esa funcionalidad puedan usarla sin depender directamente de su clase de implementación. Si más adelante decide cambiar y utilizar una implementación diferente, solo necesita cambiar la parte del código donde se crea una instancia de la implementación. El rest del código no necesita cambiar porque depende de la interfaz, no de la clase implementadora.

Esto es muy útil para crear pruebas unitarias. En la clase bajo prueba, se depende de la interfaz e inyecta una instancia de la interfaz en la clase (o una fábrica que le permite crear instancias de la interfaz según sea necesario) a través del constructor o un conjunto de propiedades. La clase usa la interfaz proporcionada (o creada) en sus métodos. Cuando vaya a escribir sus pruebas, puede simular o falsificar la interfaz y proporcionar una interfaz que responda con los datos configurados en la prueba de su unidad. Puedes hacer esto porque tu clase bajo prueba trata solo con la interfaz, no con tu implementación concreta. Cualquier clase que implemente la interfaz, incluidas las clases falsa o falsa, funcionará.

EDITAR: A continuación se muestra un enlace a un artículo donde Erich Gamma analiza su cita, “Progtwig a una interfaz, no una implementación”.

http://www.artima.com/lejava/articles/designprinciples.html

Deberías mirar Inversion of Control:

  • Martin Fowler: inversión de contenedores de control y el patrón de dependency injection
  • Wikipedia: Inversión del control

En tal escenario, no escribirías esto:

 IInterface classRef = new ObjectWhatever(); 

Usted escribiría algo como esto:

 IInterface classRef = container.Resolve(); 

Esto entraría en una configuración basada en reglas en el objeto container , y construiría el objeto real para usted, que podría ser ObjectWhatever. Lo importante es que podría reemplazar esta regla por algo que utilizara por completo otro tipo de objeto, y su código aún funcionaría.

Si dejamos IoC fuera de la mesa, puede escribir un código que sepa que puede hablar con un objeto que hace algo específico , pero no con qué tipo de objeto o cómo lo hace.

Esto sería útil al pasar parámetros.

En cuanto a su pregunta entre paréntesis “Además, ¿cómo podría escribir un método que tenga en un objeto que implemente una interfaz? ¿Es eso posible?”, En C # simplemente usaría el tipo de interfaz para el tipo de parámetro, como este:

 public void DoSomethingToAnObject(IInterface whatever) { ... } 

Esto se conecta directamente a la “conversación con un objeto que hace algo específico”. El método definido anteriormente sabe qué esperar del objeto, que implementa todo en IInterface, pero no le importa qué tipo de objeto es, solo que se adhiere al contrato, que es lo que es una interfaz.

Por ejemplo, probablemente esté familiarizado con las calculadoras y probablemente haya utilizado algunas en sus días, pero la mayoría de las veces son todas diferentes. Usted, por otro lado, sabe cómo debería funcionar una calculadora estándar, por lo que puede usarlas todas, incluso si no puede usar las características específicas que tiene cada calculadora y ninguna de las otras tiene.

Esta es la belleza de las interfaces. Puede escribir un fragmento de código que sepa que obtendrá objetos pasados ​​de los que puede esperar cierto comportamiento. No le importa qué tipo de objeto es, solo que admite el comportamiento necesario.

Déjame darte un ejemplo concreto.

Tenemos un sistema de traducción personalizado para formularios de Windows. Este sistema recorre los controles de un formulario y traduce texto en cada uno. El sistema sabe cómo manejar los controles básicos, como el tipo de control que tiene una propiedad de texto, y cosas básicas similares, pero para todo lo básico, se queda corto.

Ahora, dado que los controles heredan de clases predefinidas sobre las que no tenemos control, podríamos hacer una de estas tres cosas:

  1. Cree soporte para nuestro sistema de traducción para detectar específicamente con qué tipo de control está trabajando y traduzca los bits correctos (pesadilla de mantenimiento)
  2. Crear soporte en clases base (imposible, ya que todos los controles heredan de diferentes clases predefinidas)
  3. Añadir compatibilidad con la interfaz

Así que hicimos nr. 3. Todos nuestros controles implementan ILocalizable, que es una interfaz que nos brinda un método, la capacidad de traducir “sí mismo” en un contenedor de texto / reglas de traducción. Como tal, el formulario no necesita saber qué tipo de control ha encontrado, solo que implementa la interfaz específica, y sabe que hay un método donde puede llamar para localizar el control.

La progtwigción en una interfaz no tiene absolutamente nada que ver con interfaces abstractas como las que vemos en Java o .NET. Ni siquiera es un concepto de OOP.

Lo que realmente significa es no meterse con las partes internas de un objeto o estructura de datos. Use la Interfaz de progtwig abstracta, o API, para interactuar con sus datos. En Java o C # eso significa usar propiedades y métodos públicos en lugar de acceso de campo sin procesar. Para C eso significa usar funciones en lugar de punteros sin procesar.

EDITAR: Y con las bases de datos, significa usar vistas y procedimientos almacenados en lugar de acceso directo a la tabla.

Código a la interfaz. No la implementación no tiene NADA que ver con Java, ni su construcción de interfaz.

Este concepto se destacó en los libros Patterns / Gang of Four, pero probablemente fue mucho antes. El concepto ciertamente existió mucho antes de que Java existiera.

La construcción de la interfaz de Java se creó para ayudar en esta idea (entre otras cosas), y las personas se han centrado demasiado en la construcción como el centro del significado en lugar de la intención original. Sin embargo, es la razón por la que tenemos métodos y atributos públicos y privados en Java, C ++, C #, etc.

Significa simplemente interactuar con la interfaz pública de un objeto o sistema. No se preocupe o incluso anticipe cómo hace lo que hace internamente. No te preocupes por cómo se implementa. En código orientado a objetos, es por eso que tenemos métodos / atributos públicos vs. privados. Estamos destinados a utilizar los métodos públicos porque los métodos privados solo están ahí para su uso interno, dentro de la clase. Constituyen la implementación de la clase y se pueden cambiar según sea necesario sin cambiar la interfaz pública. Supongamos que con respecto a la funcionalidad, un método en una clase realizará la misma operación con el mismo resultado esperado cada vez que lo llame con los mismos parámetros. Permite al autor cambiar la forma en que funciona la clase, su implementación, sin romper la forma en que las personas interactúan con ella.

Y puede progtwigr en la interfaz, no en la implementación sin usar una construcción de interfaz. Puede progtwigr en la interfaz, no la implementación en C ++, que no tiene una construcción de interfaz. Puede integrar dos sistemas empresariales masivos de forma mucho más sólida siempre que interactúen a través de interfaces públicas (contratos) en lugar de llamar a métodos en objetos internos de los sistemas. Se espera que las interfaces siempre reaccionen de la misma manera esperada dados los mismos parámetros de entrada; si se implementa en la interfaz y no en la implementación. El concepto funciona en muchos lugares.

Sacude la idea de que Java Interfaces tiene algo que hacer con el concepto de ‘Progtwig para la interfaz, no la implementación’. Pueden ayudar a aplicar el concepto, pero no son el concepto.

Parece que entiende cómo funcionan las interfaces, pero no está seguro de cuándo usarlas y qué ventajas ofrecen. Aquí hay algunos ejemplos de cuándo una interfaz tendría sentido:

 // if I want to add search capabilities to my application and support multiple search // engines such as google, yahoo, live, etc. interface ISearchProvider { string Search(string keywords); } 

entonces podría crear GoogleSearchProvider, YahooSearchProvider, LiveSearchProvider, etc.

 // if I want to support multiple downloads using different protocols // HTTP, HTTPS, FTP, FTPS, etc. interface IUrlDownload { void Download(string url) } // how about an image loader for different kinds of images JPG, GIF, PNG, etc. interface IImageLoader { Bitmap LoadImage(string filename) } 

luego crea JpegImageLoader, GifImageLoader, PngImageLoader, etc.

La mayoría de los complementos y los sistemas de complementos funcionan fuera de las interfaces.

Otro uso popular es para el patrón Repositorio. Supongamos que quiero cargar una lista de códigos postales de diferentes fonts

 interface IZipCodeRepository { IList GetZipCodes(string state); } 

entonces podría crear un XMLZipCodeRepository, SQLZipCodeRepository, CSVZipCodeRepository, etc. Para mis aplicaciones web, a menudo creo repositorys XML desde el principio para poder tener algo en funcionamiento antes de que la Base de Datos SQL esté lista. Una vez que la base de datos está lista escribo un SQLRepository para reemplazar la versión XML. El rest de mi código permanece sin cambios, ya que se ejecuta fuera de las interfaces.

Los métodos pueden aceptar interfaces tales como:

 PrintZipCodes(IZipCodeRepository zipCodeRepository, string state) { foreach (ZipCode zipCode in zipCodeRepository.GetZipCodes(state)) { Console.WriteLine(zipCode.ToString()); } } 

Hace que tu código sea mucho más extensible y fácil de mantener cuando tienes grupos de clases similares. Soy un progtwigdor junior, así que no soy un experto, pero acabo de terminar un proyecto que requería algo similar.

Trabajo en un software del lado del cliente que habla con un servidor que ejecuta un dispositivo médico. Estamos desarrollando una nueva versión de este dispositivo que tiene algunos componentes nuevos que el cliente debe configurar a veces. Hay dos tipos de componentes nuevos, y son diferentes, pero también son muy similares. Básicamente, tuve que crear dos formularios de configuración, dos listas de clases, dos de todo.

Decidí que sería mejor crear una clase base abstracta para cada tipo de control que pudiera contener casi toda la lógica real, y luego tipos derivados para encargarme de las diferencias entre los dos componentes. Sin embargo, las clases base no habrían podido realizar operaciones en estos componentes si tuviera que preocuparme por los tipos todo el tiempo (bueno, podrían haberlo hecho, pero habría habido una instrucción “if” o un cambio en cada método) .

Definí una interfaz simple para estos componentes y todas las clases base hablan con esta interfaz. Ahora cuando cambio algo, prácticamente funciona en todas partes y no tengo duplicación de código.

Si progtwig en Java, JDBC es un buen ejemplo. JDBC define un conjunto de interfaces pero no dice nada sobre la implementación. Sus aplicaciones pueden escribirse contra este conjunto de interfaces. En teoría, eliges un controlador JDBC y tu aplicación simplemente funcionará. Si descubres que hay un controlador JDBC más rápido o “mejor” o más económico o por alguna razón, en teoría puedes volver a configurar tu archivo de propiedad y, sin tener que realizar ningún cambio en tu aplicación, tu aplicación seguirá funcionando.

La progtwigción en interfaces es increíble, promueve el acoplamiento flexible. Como mencionó @lassevk, Inversion of Control es un gran uso de esto.

Además, mira en los principios SÓLIDOS . aquí hay una serie de videos

Pasa por un ejemplo codificado duro (fuertemente acoplado) luego mira las interfaces, finalmente avanza a una herramienta IoC / DI (NInject)

Además de la respuesta ya seleccionada (y las diversas publicaciones informativas aquí), recomendaría mucho obtener una copia de los patrones de diseño de Head First . Es una lectura muy fácil y responderá su pregunta directamente, explicará por qué es importante y le mostrará muchos patrones de progtwigción que puede usar para hacer uso de ese principio (y otros).

Una gran cantidad de explicación por ahí, pero para hacerlo aún más simple. Tome por ejemplo una List . Uno puede implementar una lista con como:

  1. una matriz interna
  2. Una lista vinculada
  3. otra implementación

Al crear una interfaz, di una List . Solo codifica la definición de Lista o lo que significa List en realidad.

Puede usar cualquier tipo de implementación internamente, digamos una implementación de array . Pero supongamos que desea cambiar la implementación por algún motivo, por ejemplo, un error o un rendimiento. Entonces solo tiene que cambiar la statement List ls = new ArrayList() a List ls = new LinkedList() .

En ningún otro lugar en el código, tendrá que cambiar cualquier otra cosa; Porque todo lo demás se construyó sobre la definición de List .

Llegué tarde a esta pregunta, pero quiero mencionar aquí que la línea “Progtwig a una interfaz, no a una implementación” tuvo una buena discusión en el libro GoF (Gang of Four) Design Patterns.

Afirmaba, en la p. 18:

Progtwig a una interfaz, no a una implementación

No declare las variables como instancias de clases concretas concretas. En cambio, comprométase solo con una interfaz definida por una clase abstracta. Encontrará que este es un tema común de los patrones de diseño en este libro.

y encima de eso, comenzó con:

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.

Entonces, en otras palabras, no escriba sus clases para que tenga un método quack() para patos, y luego un método de bark() para perros, porque son demasiado específicos para una implementación particular de una clase (o subclase) . En su lugar, escriba el método utilizando nombres que sean lo suficientemente generales como para usarlos en la clase base, como giveSound() o move() , de modo que se puedan usar para patos, perros o incluso automóviles, y luego el cliente de su las clases solo pueden decir .giveSound() lugar de pensar si se debe usar quack() o bark() o incluso determinar el tipo antes de emitir el mensaje correcto que se enviará al objeto.

Para agregar a las publicaciones existentes, a veces la encoding en interfaces ayuda en proyectos grandes cuando los desarrolladores trabajan en componentes separados simultáneamente. Todo lo que necesita es definir las interfaces por adelantado y escribir el código en ellas, mientras que otros desarrolladores escriben el código en la interfaz que está implementando.

También es bueno para Unit Testing, puede inyectar sus propias clases (que cumplen los requisitos de la interfaz) en una clase que depende de ello

Entonces, solo para hacerlo bien, la ventaja de una interfaz es que puedo separar la llamada de un método de cualquier clase en particular. En su lugar, creo una instancia de la interfaz, donde la implementación se da desde cualquier clase que elija que implemente esa interfaz. Por lo tanto, me permite tener muchas clases, que tienen una funcionalidad similar pero ligeramente diferente y en algunos casos (los casos relacionados con la intención de la interfaz) no importa qué objeto es.

Por ejemplo, podría tener una interfaz de movimiento. Un método que hace que algo se ‘mueva’ y cualquier objeto (Persona, Coche, Gato) que implemente la interfaz de movimiento podría pasarse y se le podría indicar que se mueva. Sin el método, cada persona que conoce el tipo de clase es.

Imagine que tiene un producto llamado ‘Zebra’ que puede ampliarse mediante complementos. Encuentra los complementos al buscar DLL en algún directorio. Carga todas esas DLL y utiliza la reflexión para encontrar cualquier clase que implemente IZebraPlugin , y luego llama a los métodos de esa interfaz para comunicarse con los complementos.

Esto lo hace completamente independiente de cualquier clase de complemento específico; no importa cuáles sean las clases. Solo le importa que cumplan con la especificación de la interfaz.

Las interfaces son una forma de definir puntos de extensibilidad como este. El código que habla con una interfaz está más débilmente acoplado, de hecho no está acoplado en absoluto a ningún otro código específico. Puede interactuar con complementos escritos años más tarde por personas que nunca conocieron al desarrollador original.

You could instead use a base class with virtual functions – all plugins would be derived from the base class. But this is much more limiting because a class can only have one base class, whereas it can implement any number of interfaces.

C++ explanation.

Think of an interface as your classes public methods.

You then could create a template that ‘depends’ on these public methods in order to carry out it’s own function (it makes function calls defined in the classes public interface). Lets say this template is a container, like a Vector class, and the interface it depends on is a search algorithm.

Any algorithm class that defines the functions/interface Vector makes calls to will satisfy the ‘contract’ (as someone explained in the original reply). The algorithms don’t even need to be of the same base class; the only requirement is that the functions/methods that the Vector depends on (interface) is defined in your algorithm.

The point of all of this is that you could supply any different search algorithm/class just as long as it supplied the interface that Vector depends on (bubble search, sequential search, quick search).

You might also want to design other containers (lists, queues) that would harness the same search algorithm as Vector by having them fulfill the interface/contract that your search algorithms depends on.

This saves time (OOP principle ‘code reuse’) as you are able to write an algorithm once instead of again and again and again specific to every new object you create without over-complicating the issue with an overgrown inheritance tree.

As for ‘missing out’ on how things operate; big-time (at least in C++), as this is how most of the Standard TEMPLATE Library’s framework operates.

Of course when using inheritance and abstract classes the methodology of programming to an interface changes; but the principle is the same, your public functions/methods are your classes interface.

This is a huge topic and one of the the cornerstone principles of Design Patterns.

In Java these concrete classes all implement the CharSequence interface:

CharBuffer, String, StringBuffer, StringBuilder

These concrete classes do not have a common parent class other than Object, so there is nothing that relates them, other than the fact they each have something to do with arrays of characters, representing such, or manipulating such. For instance, the characters of String cannot be changed once a String object is instantiated, whereas the characters of StringBuffer or StringBuilder can be edited.

Yet each one of these classes is capable of suitably implementing the CharSequence interface methods:

 char charAt(int index) int length() CharSequence subSequence(int start, int end) String toString() 

In some cases Java class library classes that used to accept String have been revised to now accept the CharSequence interface. So if you have an instance of StringBuilder, instead of extracting a String object (which means instantiating a new object instance), can instead just pass the StringBuilder itself as it implements the CharSequence interface.

The Appendable interface that some classes implement has much the same kind of benefit for any situation where characters can be appended to an instance of the underlying concrete class object instance. All of these concrete classes implement the Appendable interface:

BufferedWriter, CharArrayWriter, CharBuffer, FileWriter, FilterWriter, LogStream, OutputStreamWriter, PipedWriter, PrintStream, PrintWriter, StringBuffer, StringBuilder, StringWriter, Writer

In simple terms… If I’m writing a new class Swimmer to add the functionality swim() and need to use an object of class say Dog, and this Dog class implements interface Animal which declares swim()[To better understand…you may draw a diagram as to what I am talking about]. At the top of the hierarchy(Animal) it’s very abstract while at the bottom (Dog) it’s very concrete. The way I think about “programming to interfaces” is that, as I write Swimmer class, I want to write my code against the interface that’s as far up that hierarchy which in this case is Animal object. An interface is free from implementation details and thus makes your code loosely-coupled. The implementation details can be changed with time, however it would not affect the remaining code since all you are interacting is with the interface and not the implementation. You don’t care what the implementation is like…all you know is that there will be a class that would implement the interface.

short story:Postman is asked to go home by home and receive the covers contains (letters,documents,cheques,giftcard,application,loveletter) with address written on it to deliver.

Suppose there is no cover and ask post man to go home by home and receive all the things and deliver to other person the postman can get confuse,

so better wrap it with cover(in our story it is interface) then he will do his job fine.

Now postman job is to receive and deliver the covers only..(he dont bothered what is inside in the cover).

Create type of interface not actual type, but implement with actual type.

Create to interface means your components get Fits into the rest of code easily

I give you example.

you have AirPlane interface as below.

 interface Airplane{ parkPlane(); servicePlane(); } 

Suppose you have methods in your Controller class of Planes like

 parkPlane(Airplane plane) 

y

 servicePlane(Airplane plane) 

implemented in your program. It will not BREAK your code. I mean, it need not to change as long as it accepts arguments as AirPlane .

Because it will accept any Airplane despite of actual type, flyer , highflyr , fighter , etc.

Also, in a collection:

List plane; // Will take all your planes.

The following example will clear your understanding.


You have a fighter plane that implements it, so

 public class Fighter implements Airplane { public void parkPlane(){ // Specific implementations for fighter plane to park } public void servicePlane(){ // Specific implementatoins for fighter plane to service. } } 

The same thing for HighFlyer and other clasess:

 public class HighFlyer implements Airplane { public void parkPlane(){ // Specific implementations for HighFlyer plane to park } public void servicePlane(){ // specific implementatoins for HighFlyer plane to service. } } 

Now think your controller classes using AirPlane several times,

Suppose your Controller class is ControlPlane like below,

 public Class ControlPlane{ AirPlane plane; // so much method with AirPlane reference are used here... } 

here magic comes as

you may make your new AirPlane type instances as many as you want and you are not changing

code of ControlPlane class.

you can add instance..

 JumboJetPlane // implementing AirPlane interface. AirBus // implementing AirPlane interface. 

you may remove instances.. of previously created types too.

Q: – … “You could use any class that implements interface?”
A: – Yes.

Q: -… “When would you need to do that?”
A: – Each time you need a class(es) that implements interface(s).

Note: we couldn’t instantiate an interface not implemented by a classTrue.

  • ¿por qué?
  • because interface has only methods prototypes, not definitions (just functions names, not their logic)

AnIntf anInst = new Aclass();
// we could do this only if Aclass implements AnIntf.
// anInst will have Aclass reference.


Nota:
Now we could understand what happend if Bclass and Cclass implements same Dintf.

 Dintf bInst = new Bclass(); // now we could call all Dintf functions implemented (defined) in Bclass. Dintf cInst = new Cclass(); // now we could call all Dintf functions implemented (defined) in Cclass. 

What we have:
same interface prototypes (functions names in interface), and call different implementations.

Bibliografía:
Prototypes – wikipedia

Interface is like contract where you want your implementation class to implement methods written in contract(Interface).Since java does not provide multiple inheritance,programming to interface is a good way to achieve purpose of multiple inheritance.If you have a class A that is already extending some other class B but you want that class A should also follow certain guidelines or implement certain contract then you can do so by programming to interface strategy.

It can be advantageous to program to interfaces, even when we are not depending on abstractions.

Programming to interfaces forces us to use a contextually appropriate subset of an object. That helps because it:

  1. prevents us from doing contextually inappropriate things, and
  2. lets us safely change the implementation in the future.

For example, consider a Person class that implements the Friend and the Employee interface.

 class Person implements AbstractEmployee, AbstractFriend { } 

In the context of the person’s birthday, we program to the Friend interface, to prevent treating the person like an Employee .

 function party() { const friend: Friend = new Person("Kathryn"); friend.HaveFun(); } 

In the context of the person’s work, we program to the Employee interface, to prevent blurring workplace boundaries.

 function workplace() { const employee: Employee = new Person("Kathryn"); employee.DoWork(); } 

Estupendo. We have behaved appropriately in different contexts, and our software is working well.

Far into the future, if our business changes to work with dogs, we can change the software fairly easily. First, we create Dog class that implements both Friend and Employee . Then, we safely change new Person() to new Dog() . Even if both functions have thousands of lines of code, that simple edit will work because we know the following are true:

  1. Function party uses only the Friend subset of Person .
  2. Function workplace uses only the Employee subset of Person .
  3. Class Dog implements both the Friend and Employee interfaces.

On the other hand, if either party or workplace were to have programmed against Person , there would be a risk of both having Person -specific code. Changing from Person to Dog would require us to comb through the code to extirpate any Person -specific code that Dog does not support.

The moral : programming to interfaces helps our code to behave appropriately and to be ready for change. It also prepares our code to depend on abstractions, which brings even more advantages.

Also I see a lot of good and explanatory answers here, so I want to give my point of view here, including some extra information what I noticed when using this method.

Unit testing

For the last two years, I have written a hobby project and I did not write unit tests for it. After writing about 50K lines I found out it would be really necessary to write unit tests. I did not use interfaces (or very sparingly) … and when I made my first unit test, I found out it was complicated. ¿Por qué?

Because I had to make a lot of class instances, used for input as class variables and/or parameters. So the tests look more like integration tests (having to make a complete ‘framework’ of classes since all was tied together).

Fear of interfaces So I decided to use interfaces. My fear was that I had to implement all functionality everywhere (in all used classes) multiple times. In some way this is true, however, by using inheritance it can be reduced a lot.

Combination of interfaces and inheritance I found out the combination is very good to be used. I give a very simple example.

 public interface IPricable { int Price { get; } } public interface ICar : IPricable public abstract class Article { public int Price { get { return ... } } } public class Car : Article, ICar { // Price does not need to be defined here } 

This way copying code is not necessary, while still having the benefit of using a car as interface (ICar).

Let’s start out with some definitions first:

Interface n. The set of all signatures defined by an object’s operations is called the interface to the object

Type n. A particular interface

A simple example of an interface as defined above would be all the PDO object methods such as query() , commit() , close() etc., as a whole, not separately. These methods, ie its interface define the complete set of messages, requests that can be sent to the object.

A type as defined above is a particular interface. I will use the made-up shape interface to demonstrate: draw() , getArea() , getPerimeter() etc..

If an object is of the Database type we mean that it accepts messages/requests of the database interface, query() , commit() etc.. Objects can be of many types. You can have a database object be of the shape type as long as it implements its interface, in which case this would be sub-typing .

Many objects can be of many different interfaces/types and implement that interface differently. This allows us to substitute objects, letting us choose which one to use. Also known as polymorphism.

The client will only be aware of the interface and not the implementation.

So in essence programming to an interface would involve making some type of abstract class such as Shape with the interface only specified ie draw() , getCoordinates() , getArea() etc.. And then have different concrete classes implement those interfaces such as a Circle class, Square class, Triangle class. Hence program to an interface not an implementation.

Program to an interface allows to change implementation of contract defined by interface seamlessly. It allows loose coupling between contract and specific implementations.

IInterface classRef = new ObjectWhatever()

You could use any class that implements IInterface? When would you need to do that?

Have a look at this SE question for good example.

Why should the interface for a Java class be preferred?

does using an Interface hit performance?

if so how much?

Sí. It will have slight performance overhead in sub-seconds. But if your application has requirement to change the implementation of interface dynamically, don’t worry about performance impact.

how can you avoid it without having to maintain two bits of code?

Don’t try to avoid multiple implementations of interface if your application need them. In absence of tight coupling of interface with one specific implementation, you may have to deploy the patch to change one implementation to other implementation.

One good use case: Implementation of Strategy pattern:

Real World Example of the Strategy Pattern

I don’t retain interface s are the most important thing in a language: it’s more commonly used the class inheriting. But anyway they are important!
For example (this is Java code, but it can simply adapted to C# or many other languages):

 interface Convertable { T convert(); } public class NumerableText implements Convertable { private String text = ""; public NumerableText() { } public NumerableText(String text) { this.text = text; } public String getText() { return this.text; } public void setText(String text) { this.text = text; } public Integer convert() { return this.text.hashCode(); } } public class NumerableTextArray implements Convertable { private String[] textArray = ""; public NumerableTextArray() { } public NumerableTextArray(String[] textArray) { this.textArray = textArray; } public String[] getTextArray() { return this.textArray; } public void setTextArray(String[] text) { this.textArray = textArray; } public Integer convert() { Integer value = 0; for (String text : textArray) value += text.hashCode(); return value; } } public class Foo { public static void main() { Convertable num1 = new NumerableText("hello"); Convertable num2 = new NumerableTextArray(new String[] { "test n°1", "test n°2" }); System.out.println(String.valueOf(num1.convert())); System.out.println(String.valueOf(num2.convert())); //Here are you two numbers generated from two classes of different type, but both with the method convert(), which allows you to get that number. } } 

Program to interface means dont provide hard codes right the way, means your codes should be extended without break the previous functionality….. just extensions not editing the prev codes