He visto esto mencionado varias veces y no tengo claro qué 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 el uso correcto.
¿Es así si tuvieras que hacer:
IInterface classRef = new ObjectWhatever()
¿Podrías usar cualquier clase que implemente IInterface
? ¿Cuándo necesitarías hacer eso? Lo único en lo que puedo pensar es si tiene un método y no está seguro de qué objeto se pasará, excepto si se implementa IInterface
. No puedo pensar con qué frecuencia necesitarías hacer eso.
Además, ¿cómo podría escribir un método que incorpore un objeto que implemente una interfaz? ¿Es eso posible?
language-agnostic
oop
interface
Damien
fuente
fuente
Respuestas:
Aquí hay algunas respuestas maravillosas a estas preguntas que incluyen todo tipo de detalles sobre interfaces y código de acoplamiento flexible, inversión de control, etc. Hay algunas discusiones bastante intensas, por lo que me gustaría aprovechar la oportunidad para desglosar un poco para comprender por qué una interfaz es útil.
Cuando comencé a exponerme a las interfaces, 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 vi las interfaces como una forma más débil de herencia y pensé, "¿por qué molestarse?" En cierto sentido, tenía razón, puedes 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:
Claramente, estos dos objetos no tienen nada en común en términos de herencia directa. Pero, se podría decir que ambos son molestos.
Digamos que nuestro juego necesita tener algún tipo de cosa aleatoria que moleste al jugador cuando cena. Esto podría ser un
HouseFly
o unTelemarketer
o ambas, pero ¿cómo permitir ambas con una sola función? ¿Y cómo le pides a cada tipo diferente de objeto que "haga lo molesto" de la misma manera?La clave para darse cuenta es que tanto a
Telemarketer
comoHouseFly
comparten un comportamiento común interpretado libremente aunque no sean nada similares en términos de modelarlos. Entonces, hagamos una interfaz que ambos puedan implementar: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 satisfacer el contrato de
IPest
ese contrato es simple. Solo tienes que hacerloBeAnnoying
. En este sentido, podemos modelar lo siguiente:Aquí tenemos un comedor que acepta una cantidad de comensales y varias plagas. Tenga en cuenta el uso de la interfaz. Esto significa que en nuestro pequeño mundo, un miembro de la
pests
matriz podría ser unTelemarketer
objeto o unHouseFly
objeto.El
ServeDinner
método 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: cada plaga tiene instrucciones de ser molesta a través de laIPest
interfaz. De esta manera, podemos tener ambas cosas fácilmenteTelemarketers
yHouseFlys
ser molestos en cada una de sus formas: solo nos importa que tengamos algo en elDiningRoom
objeto que sea una plaga, realmente no nos importa lo que es y no podrían tener nada en común con otros.Este ejemplo de pseudocódigo muy ingenioso (que se prolongó mucho más de lo que esperaba) simplemente tiene la intención de ilustrar el tipo de cosas que finalmente me enciende la luz en términos de cuándo podríamos usar una interfaz. Pido disculpas de antemano por la tontería del ejemplo, pero espero que ayude a su comprensión. Y, para estar seguros, las otras respuestas publicadas que ha recibido aquí realmente cubren toda la gama del uso de interfaces hoy en día en patrones de diseño y metodologías de desarrollo.
fuente
BeAnnoying
como no operativos ; esta interfaz puede existir en lugar de, o además de, la interfaz para cosas que son molestas (si ambas interfaces existen, la interfaz "cosas que son molestas" debería heredar de la interfaz "cosas que podrían ser molestas"). La desventaja de usar tales interfaces es que las implementaciones pueden verse cargadas con la implementación de un número "molesto" de métodos de código auxiliar. La ventaja es que ...IPest[]
son referencias IPest, puede llamarBeAnnoying()
porque tienen ese método, mientras que no puede llamar a otros métodos sin una conversión. Sin embargo, cadaBeAnnoying()
método individual de los objetos será llamado.El ejemplo específico que solía dar a los estudiantes es que deberían escribir
en vez de
Estos se ven exactamente iguales en un programa corto, pero si continúa utilizando
myList
100 veces en su programa, puede comenzar a ver la diferencia. La primera declaración asegura que solo se invocan métodosmyList
definidos por laList
interfaz (por lo que no hayArrayList
métodos específicos). Si ha programado para la interfaz de esta manera, más adelante puede decidir que realmente necesitay solo tienes que cambiar tu código en ese lugar. Ya sabe que el resto de su código no hace nada que se rompa al cambiar la implementación porque programó la interfaz .
Los beneficios son aún más obvios (creo) cuando se habla de parámetros de métodos y valores de retorno. Toma esto por ejemplo:
Esa declaración de método lo vincula a dos implementaciones concretas (
ArrayList
yHashMap
). Tan pronto como se llame a ese método desde otro código, cualquier cambio en esos tipos probablemente significa que también tendrá que cambiar el código de llamada. Sería mejor programar en las interfaces.Ahora no importa qué tipo de
List
retorno, o qué tipo deMap
pasa como parámetro. Los cambios que realice dentro deldoSomething
método no lo obligarán a cambiar el código de llamada.fuente
La programación en una interfaz dice: "Necesito esta funcionalidad y no me importa de dónde viene".
Considere (en Java), la
List
interfaz frente a losArrayList
yLinkedList
concretas clases. 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 la iteración, elegiría unList
(y eso es el 99% del tiempo). Si sé que necesito insertar / eliminar en tiempo constante desde cualquier extremo de la lista, podría elegir laLinkedList
implementación concreta (o más probablemente, usar la interfaz de cola ). Si sé que necesito acceso aleatorio por índice, elegiría laArrayList
clase concreta.fuente
El uso de interfaces es un factor clave para hacer que su código sea fácilmente comprobable, además de eliminar acoplamientos innecesarios entre sus clases. Al crear una interfaz que define las operaciones en su clase, permite que las clases que quieran usar esa funcionalidad puedan usarla sin depender directamente de su clase de implementación. Si más adelante decide cambiar y usar una implementación diferente, solo necesita cambiar la parte del código donde se instancia la implementación. El resto 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, depende de la interfaz e inyecta una instancia de la interfaz en la clase (o en una fábrica que le permite construir instancias de la interfaz según sea necesario) a través del constructor o un configurador de propiedades. La clase utiliza la interfaz proporcionada (o creada) en sus métodos. Cuando vaya a escribir sus pruebas, puede simular o simular la interfaz y proporcionar una interfaz que responda con los datos configurados en la prueba de su unidad. Puede hacerlo porque su clase bajo prueba solo trata con la interfaz, no con su implementación concreta. Cualquier clase que implemente la interfaz, incluida su clase falsa o falsa, funcionará.
EDITAR: a continuación hay un enlace a un artículo donde Erich Gamma discute su cita, "Programa para una interfaz, no una implementación".
http://www.artima.com/lejava/articles/designprinciples.html
fuente
La programació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 OOP.
Lo que significa es no jugar con los elementos internos de un objeto o estructura de datos. Utilice la interfaz del programa abstracto, o API, para interactuar con sus datos. En Java o C # eso significa usar propiedades y métodos públicos en lugar de acceso a campo sin procesar. Para C eso significa usar funciones en lugar de punteros sin formato.
EDITAR: Y con las bases de datos significa usar vistas y procedimientos almacenados en lugar de acceso directo a la tabla.
fuente
Debería analizar la Inversión de control:
En tal escenario, no escribirías esto:
Escribirías algo como esto:
Esto entraría en una configuración basada en reglas en el
container
objeto y construiría el objeto real para usted, que podría ser ObjectWhatever. Lo importante es que podría reemplazar esta regla con algo que usara otro tipo de objeto por completo, y su código aún funcionaría.Si dejamos la IoC fuera de la tabla, puede escribir código que sepa que puede hablar con un objeto que hace algo específico , pero no 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 incorpore un objeto que implemente una interfaz? ¿Es eso posible?", En C # simplemente usaría el tipo de interfaz para el tipo de parámetro, de esta manera:
Esto se conecta directamente a "hablar 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 usado bastantes 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 usarlos todos, incluso si no puede usar las características específicas que tiene cada calculadora que ninguna de las otras tiene.
Esta es la belleza de las interfaces. Puede escribir un fragmento de código, que sepa que obtendrá objetos que le pueden pasar de los que puede esperar cierto comportamiento. No importa qué tipo de objeto sea, solo que es compatible con 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 controles básicos, como la propiedad de tipo de control que tiene un texto, y cosas básicas similares, pero para cualquier cosa básica, se queda corto.
Ahora, dado que los controles heredan de clases predefinidas sobre las que no tenemos control, podríamos hacer una de tres cosas:
Entonces hicimos nr. 3. Todos nuestros controles implementan ILocalizable, que es una interfaz que nos brinda un método, la capacidad de traducir "a 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 al que puede llamar para localizar el control.
fuente
Código para 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 de Patrones / Banda de cuatro, pero probablemente ya existía mucho antes. El concepto ciertamente existía mucho antes de que Java existiera.
La construcción de la Interfaz 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 un objeto o la interfaz pública del sistema. No se preocupe ni anticipe cómo hace lo que hace internamente. No te preocupes por cómo se implementa. En el código orientado a objetos, es por eso que tenemos métodos / atributos públicos versus privados. Estamos destinados a usar los métodos públicos porque los métodos privados están ahí solo para 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. Suponga 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 cómo funciona la clase, su implementación, sin romper la forma en que las personas interactúan con ella.
Y puede programar en la interfaz, no en la implementación, sin usar nunca una construcción de interfaz. Puede programar en la interfaz, no la implementación en C ++, que no tiene una construcción de interfaz. Puede integrar dos sistemas empresariales masivos de manera mucho más sólida siempre que interactúen a través de interfaces públicas (contratos) en lugar de invocar métodos en objetos internos de los sistemas. Se espera que las interfaces reaccionen siempre 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.
Sacuda la idea de que las interfaces Java tienen algo que ver con el concepto de "Programa para la interfaz, no la implementación". Ellos pueden ayudar a aplicar el concepto, pero son no el concepto.
fuente
Parece que comprende 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:
entonces podría crear GoogleSearchProvider, YahooSearchProvider, LiveSearchProvider, etc.
luego cree JpegImageLoader, GifImageLoader, PngImageLoader, etc.
La mayoría de los sistemas de complementos y complementos funcionan fuera de las interfaces.
Otro uso popular es para el patrón de repositorio. Digamos que quiero cargar una lista de códigos postales de diferentes fuentes
entonces podría crear un XMLZipCodeRepository, SQLZipCodeRepository, CSVZipCodeRepository, etc. Para mis aplicaciones web, a menudo creo repositorios XML desde el principio para poder poner en marcha algo 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 resto de mi código permanece sin cambios ya que se ejecuta únicamente fuera de las interfaces.
Los métodos pueden aceptar interfaces como:
fuente
Hace que su código sea mucho más extensible y más fácil de mantener cuando tiene conjuntos de clases similares. Soy un programador junior, así que no soy un experto, pero acabo de terminar un proyecto que requería algo similar.
Trabajo en 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 clases de listas, dos de todo.
Decidí que sería mejor crear una clase base abstracta para cada tipo de control que contendría casi toda la lógica real, y luego los tipos derivados para ocuparse 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 declaración "if" o 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.
fuente
Mucha explicación por ahí, pero para hacerlo aún más simple. Tomemos por ejemplo a
List
. Se puede implementar una lista con como:Al construir una interfaz, diga a
List
. Solo codifica en cuanto a la definición de Lista o lo queList
significa en realidad.Puede usar cualquier tipo de implementación internamente, digamos una
array
implementación. Pero suponga que desea cambiar la implementación por alguna razón, digamos un error o rendimiento. Entonces solo tienes que cambiar la declaraciónList<String> ls = new ArrayList<String>()
aList<String> ls = new LinkedList<String>()
.En ninguna otra parte del código, tendrá que cambiar algo más; Porque todo lo demás se basó en la definición de
List
.fuente
Si programa en Java, JDBC es un buen ejemplo. JDBC define un conjunto de interfaces pero no dice nada sobre la implementación. Sus aplicaciones se pueden escribir en este conjunto de interfaces. En teoría, elige un controlador JDBC y su aplicación simplemente funcionaría. Si descubre que hay un controlador JDBC más rápido o "mejor" o más barato o por alguna razón, puede volver a configurar en teoría su archivo de propiedades, y sin tener que hacer ningún cambio en su aplicación, su aplicación aún funcionaría.
fuente
La programación en Interfaces es increíble, promueve el acoplamiento suelto. Como @lassevk mencionó, la Inversión de Control es un gran uso de esto.
Además, busque en los principios SOLIDOS . aquí hay una serie de videos
Pasa por un código rígido (ejemplo fuertemente acoplado), luego mira las interfaces y finalmente pasa a una herramienta IoC / DI (NInject)
fuente
Llegué tarde a esta pregunta, pero quiero mencionar aquí que la línea "Programa para una interfaz, no una implementación" tuvo una buena discusión en el libro GoF (Gang of Four) Design Patterns.
Declaró, en la p. 18:
y encima de eso, comenzó con:
En otras palabras, no lo escriba en sus clases para que tenga un
quack()
método para patos, y luego unbark()
método para perros, porque son demasiado específicos para una implementación particular de una clase (o subclase). En su lugar, escriba el método usando nombres que sean lo suficientemente generales como para usarse en la clase base, comogiveSound()
omove()
, para que puedan usarse para patos, perros o incluso automóviles, y luego el cliente de sus clases puede decir en.giveSound()
lugar de pensando en usarquack()
obark()
incluso determinar el tipo antes de emitir el mensaje correcto que se enviará al objeto.fuente
Además de la respuesta ya seleccionada (y las diversas publicaciones informativas aquí), recomendaría encarecidamente tomar una copia de Head First Design Patterns . Es una lectura muy fácil y responderá su pregunta directamente, explicará por qué es importante y le mostrará muchos patrones de programación que puede usar para hacer uso de ese principio (y otros).
fuente
Para agregar a las publicaciones existentes, a veces la codificación de interfaces ayuda en proyectos grandes cuando los desarrolladores trabajan en componentes separados simultáneamente. Todo lo que necesita es definir interfaces por adelantado y escribir código en ellas mientras otros desarrolladores escriben código en la interfaz que está implementando.
fuente
También es bueno para Unit Testing, puede inyectar sus propias clases (que cumplan los requisitos de la interfaz) en una clase que depende de ella
fuente
Puede ser ventajoso programar en interfaces, incluso cuando no dependemos de abstracciones.
La programación en interfaces nos obliga a usar un subconjunto contextualmente apropiado de un objeto . Eso ayuda porque:
Por ejemplo, considere una
Person
clase que implementa elFriend
y laEmployee
interfaz.En el contexto del cumpleaños de la persona, programamos la
Friend
interfaz para evitar tratar a la persona como unEmployee
.En el contexto del trabajo de la persona, programamos en la
Employee
interfaz para evitar difuminar los límites del lugar de trabajo.Excelente. Nos hemos comportado adecuadamente en diferentes contextos y nuestro software funciona bien.
En el futuro, si nuestro negocio cambia para trabajar con perros, podemos cambiar el software con bastante facilidad. Primero, creamos una
Dog
clase que implementa ambosFriend
yEmployee
. Luego, cambiamos de manera seguranew Person()
anew Dog()
. Incluso si ambas funciones tienen miles de líneas de código, esa edición simple funcionará porque sabemos que lo siguiente es cierto:party
usa solo elFriend
subconjunto dePerson
.workplace
usa solo elEmployee
subconjunto dePerson
.Dog
implementa las interfacesFriend
yEmployee
.Por otro lado, si cualquiera
party
oworkplace
debían haber programado contraPerson
, habría un riesgo de ambos conPerson
código específico de. Cambiar dePerson
aDog
requeriría que revisemos el código para extirpar cualquierPerson
código específico queDog
no sea compatible.La moraleja : programar en interfaces ayuda a que nuestro código se comporte de manera adecuada y esté listo para el cambio. También prepara nuestro código para depender de abstracciones, lo que trae aún más ventajas.
fuente
Si estoy escribiendo una nueva clase
Swimmer
para agregar la funcionalidadswim()
y necesito usar un objeto de claseDog
, digamos , y estaDog
clase implementa una interfazAnimal
que declaraswim()
.En la parte superior de la jerarquía (
Animal
), es muy abstracto, mientras que en la parte inferior (Dog
) es muy concreto. La forma en que pienso sobre "programar en interfaces" es que, mientras escribo laSwimmer
clase, quiero escribir mi código en la interfaz que está tan arriba en esa jerarquía, que en este caso es unAnimal
objeto. Una interfaz está libre de detalles de implementación y, por lo tanto, hace que su código se acople libremente.Los detalles de implementación se pueden cambiar con el tiempo, sin embargo, no afectaría el código restante ya que todo lo que está interactuando es con la interfaz y no con la implementación. No le importa cómo es la implementación ... todo lo que sabe es que habrá una clase que implementará la interfaz.
fuente
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 lugar de crear una instancia de la interfaz, donde la implementación se da desde la 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 me importa qué objeto sea.
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 se pueda pasar y se le diga que se mueva. Sin el método, cada uno sabe el tipo de clase que es.
fuente
Imagine que tiene un producto llamado 'Zebra' que se puede ampliar con complementos. Encuentra los complementos buscando DLL en algún directorio. Carga todas esas DLL y usa 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ífica; no le importa cuáles son 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 a ningún otro código específico. Puede interactuar con complementos escritos años después por personas que nunca han conocido al desarrollador original.
En su lugar, podría usar una clase base con funciones virtuales: todos los complementos se derivarían de la clase base. Pero esto es mucho más limitante porque una clase solo puede tener una clase base, mientras que puede implementar cualquier cantidad de interfaces.
fuente
Explicación de C ++.
Piense en una interfaz como los métodos públicos de sus clases.
Luego puede crear una plantilla que 'dependa' de estos métodos públicos para llevar a cabo su propia función (hace que las llamadas a funciones definidas en la interfaz pública de las clases). Digamos que esta plantilla es un contenedor, como una clase Vector, y la interfaz de la que depende es un algoritmo de búsqueda.
Cualquier clase de algoritmo que defina las funciones / interfaz a las que hace Vector Vector satisfará el 'contrato' (como alguien explicó en la respuesta original). Los algoritmos ni siquiera necesitan ser de la misma clase base; el único requisito es que las funciones / métodos de los que depende el Vector (interfaz) estén definidos en su algoritmo.
El punto de todo esto es que puede proporcionar cualquier algoritmo / clase de búsqueda diferente siempre que proporcione la interfaz de la que depende Vector (búsqueda de burbujas, búsqueda secuencial, búsqueda rápida).
También es posible que desee diseñar otros contenedores (listas, colas) que aprovechen el mismo algoritmo de búsqueda que Vector haciendo que cumplan con la interfaz / contrato del que dependen sus algoritmos de búsqueda.
Esto ahorra tiempo (principio de OOP 'reutilización de código') ya que puede escribir un algoritmo una vez en lugar de una y otra y otra vez específico para cada nuevo objeto que cree sin complicar demasiado el problema con un árbol de herencia demasiado grande.
En cuanto a 'perderse' cómo funcionan las cosas; a lo grande (al menos en C ++), ya que así es como funciona la mayor parte del marco de la biblioteca TEMPLATE estándar.
Por supuesto, cuando se usan clases de herencia y abstractas, la metodología de programación para una interfaz cambia; pero el principio es el mismo, sus funciones / métodos públicos son su interfaz de clases.
Este es un tema enorme y uno de los principios fundamentales de los patrones de diseño.
fuente
En Java, estas clases concretas implementan la interfaz CharSequence:
Estas clases concretas no tienen una clase principal común que no sea Object, por lo que no hay nada que las relacione, aparte del hecho de que cada una tiene algo que ver con conjuntos de caracteres, que representan o manipulan. Por ejemplo, los caracteres de String no se pueden cambiar una vez que se crea una instancia de un objeto String, mientras que los caracteres de StringBuffer o StringBuilder se pueden editar.
Sin embargo, cada una de estas clases es capaz de implementar adecuadamente los métodos de interfaz CharSequence:
En algunos casos, las clases de la biblioteca de clases Java que solían aceptar String se han revisado para que ahora acepten la interfaz CharSequence. Entonces, si tiene una instancia de StringBuilder, en lugar de extraer un objeto String (lo que significa crear una instancia de un nuevo objeto), en su lugar, puede pasar el StringBuilder mismo mientras implementa la interfaz CharSequence.
La interfaz Appendable que implementan algunas clases tiene el mismo tipo de beneficio para cualquier situación en la que los caracteres se pueden agregar a una instancia de la instancia de objeto de clase concreta subyacente. Todas estas clases concretas implementan la interfaz Appendable:
fuente
CharSequence
es tan anémica. Desearía que Java y .NET hubieran permitido que las interfaces tuvieran una implementación predeterminada, para que las personas no redujeran las interfaces con el único fin de minimizar el código repetitivo. Dada cualquierCharSequence
implementación legítima , uno podría emular la mayoría de las funciones deString
usar solo los cuatro métodos anteriores, pero muchas implementaciones podrían realizar esas funciones de manera mucho más eficiente de otras maneras. Desafortunadamente, incluso si una implementación particular deCharSequence
contiene todo en un solochar[]
y podría realizar muchos ...indexOf
rápidamente, no hay forma de que una persona que llama que no esté familiarizada con una implementación particularCharSequence
pueda pedirle que lo haga en lugar de tener que usarcharAt
para examinar cada personaje individual.Breve historia: se le pide a un cartero que vaya a casa después de casa y reciba las portadas que contiene (cartas, documentos, cheques, tarjetas de regalo, solicitud, carta de amor) con la dirección escrita para entregar.
Suponga que no hay cobertura y pídale al cartero que se vaya a casa después de casa y reciba todas las cosas y se las entregue a otras personas, el cartero puede confundirse.
Así que mejor envuélvelo con tapa (en nuestra historia es la interfaz), entonces él hará su trabajo bien.
Ahora, el trabajo del cartero es recibir y entregar las portadas únicamente (no le molestaría lo que hay dentro de la portada).
Cree un tipo de tipo
interface
no real, pero impleméntelo con el tipo real.Crear para la interfaz significa que sus componentes se ajustan fácilmente al resto del código
Te doy un ejemplo.
tiene la interfaz AirPlane como se muestra a continuación.
Supongamos que tiene métodos en su clase de Controlador de Planos como
y
implementado en su programa. No romperá su código. Quiero decir, no necesita cambiar mientras acepte argumentos como
AirPlane
.Debido a que aceptará cualquier avión a pesar de tipo real,
flyer
,highflyr
,fighter
, etc.Además, en una colección:
List<Airplane> plane;
// Tomará todos tus aviones.El siguiente ejemplo aclarará su comprensión.
Tienes un avión de combate que lo implementa, así que
Lo mismo para HighFlyer y otras clases:
Ahora piense que sus clases de controlador usan
AirPlane
varias veces,Supongamos que su clase de controlador es ControlPlane como a continuación,
Aquí viene la magia, ya que puede hacer que sus nuevas
AirPlane
instancias de tipo sean tantas como desee y no está cambiando el código deControlPlane
clase.Puedes agregar una instancia ...
También puede eliminar instancias de tipos creados previamente.
fuente
Una interfaz es como un contrato, donde desea que su clase de implementación implemente métodos escritos en el contrato (interfaz). Como Java no proporciona herencia múltiple, "programar para interactuar" es una buena manera de lograr herencia múltiple.
Si tiene una clase A que ya está ampliando alguna otra clase B, pero desea que esa clase A también siga ciertas pautas o implemente un determinado contrato, puede hacerlo mediante la estrategia de "programación a interfaz".
fuente
Nota: No pudimos crear una instancia de una interfaz no implementada por una clase - Verdadero.
Nota: Ahora podríamos entender qué pasaría si Bclass y Cclass implementaran el mismo Dintf.
Lo que tenemos: los mismos prototipos de interfaz (nombres de funciones en la interfaz) y llamadas a diferentes implementaciones.
Bibliografía: prototipos - wikipedia
fuente
El programa a una interfaz permite cambiar la implementación del contrato definido por la interfaz sin problemas. Permite un acoplamiento flexible entre el contrato y las implementaciones específicas.
Eche un vistazo a esta pregunta SE para un buen ejemplo.
¿Por qué debería preferirse la interfaz para una clase Java?
Si. Tendrá una ligera sobrecarga de rendimiento en segundos secundarios. Pero si su aplicación tiene el requisito de cambiar la implementación de la interfaz de forma dinámica, no se preocupe por el impacto en el rendimiento.
No intente evitar múltiples implementaciones de interfaz si su aplicación las necesita. En ausencia de un acoplamiento estrecho de la interfaz con una implementación específica, es posible que deba implementar el parche para cambiar una implementación a otra.
Un buen caso de uso: Implementación del patrón de estrategia:
Ejemplo del mundo real del patrón de estrategia
fuente
programa para una interfaz es un término del libro GOF. No diría directamente que tiene que ver con la interfaz de Java sino con interfaces reales. para lograr una separación de capa limpia, necesita crear cierta separación entre sistemas, por ejemplo: Digamos que tenía una base de datos concreta que desea usar, nunca "programaría en la base de datos", sino que "programaría en la interfaz de almacenamiento". Del mismo modo, nunca "programaría para un servicio web" sino que programaría para una "interfaz de cliente". Esto es para que pueda cambiar fácilmente las cosas.
Me parece que estas reglas me ayudan:
1 . Usamos una interfaz Java cuando tenemos múltiples tipos de un objeto. Si solo tengo un solo objeto, no veo el punto. si hay al menos dos implementaciones concretas de alguna idea, entonces usaría una interfaz java.
2 . si, como dije anteriormente, desea llevar el desacoplamiento de un sistema externo (sistema de almacenamiento) a su propio sistema (base de datos local), entonces también use una interfaz.
observe cómo hay dos formas de considerar cuándo usarlos. espero que esto ayude.
fuente
También veo muchas respuestas buenas y explicativas aquí, así que quiero dar mi punto de vista aquí, incluida información adicional de lo que noté al usar este método.
Examen de la unidad
Durante los últimos dos años, he escrito un proyecto de pasatiempo y no escribí pruebas unitarias para él. Después de escribir alrededor de 50K líneas descubrí que sería realmente necesario escribir pruebas unitarias. No utilicé interfaces (o muy poco) ... y cuando hice mi primera prueba de unidad, descubrí que era complicado. ¿Por qué?
Debido a que tuve que hacer muchas instancias de clase, utilizadas para la entrada como variables de clase y / o parámetros. Entonces las pruebas se parecen más a las pruebas de integración (tener que hacer un 'marco' completo de clases ya que todo estaba unido).
Miedo a las interfaces Así que decidí usar interfaces. Mi temor era que tenía que implementar todas las funciones en todas partes (en todas las clases usadas) varias veces. De alguna manera, esto es cierto, sin embargo, al usar la herencia se puede reducir mucho.
Combinación de interfaces y herencia Descubrí que la combinación es muy buena para ser utilizada. Doy un ejemplo muy simple.
De esta forma, no es necesario copiar el código, mientras se tiene la ventaja de utilizar un automóvil como interfaz (ICar).
fuente
Comencemos con algunas definiciones primero:
Interfaz n. El conjunto de todas las firmas definidas por las operaciones de un objeto se denomina interfaz con el objeto.
Escriba n. Una interfaz particular
Un ejemplo simple de una interfaz como se define anteriormente sería todos los métodos de objeto PDO tales como
query()
,commit()
,close()
etc., en su conjunto, no por separado. Estos métodos, es decir, su interfaz definen el conjunto completo de mensajes, solicitudes que pueden enviarse al objeto.Un tipo como se definió anteriormente es una interfaz particular. Voy a utilizar la interfaz de forma maquillada para demostrar:
draw()
,getArea()
,getPerimeter()
etc ..Si un objeto es del tipo Base de datos, queremos decir que acepta mensajes / solicitudes de la interfaz de la base de datos
query()
,commit()
etc. Los objetos pueden ser de muchos tipos. Puede hacer que un objeto de la base de datos sea del tipo de forma siempre que implemente su interfaz, en cuyo caso esto sería un subtipo .Muchos objetos pueden ser de muchas interfaces / tipos diferentes e implementar esa interfaz de manera diferente. Esto nos permite sustituir objetos, permitiéndonos elegir cuál usar. También conocido como polimorfismo.
El cliente solo conocerá la interfaz y no la implementación.
Entonces, en esencia, programar en una interfaz implicaría hacer algún tipo de clase abstracta, como
Shape
con la interfaz solo especificadadraw()
, es decirgetCoordinates()
,getArea()
etc. Y luego hacer que diferentes clases concretas implementen esas interfaces, como una clase Circle, una clase Square, una clase Triangle. Por lo tanto, programe una interfaz, no una implementación.fuente
"Programa para interfaz" significa que no debe proporcionar el código duro de la manera correcta, lo que significa que su código debe ampliarse sin romper la funcionalidad anterior. Solo extensiones, no editando el código anterior.
fuente