La razón de las interfaces realmente se me escapa. Por lo que entiendo, es una especie de solución alternativa para la herencia múltiple inexistente que no existe en C # (o eso me dijeron).
Todo lo que veo es que usted predefine algunos miembros y funciones, que luego deben redefinirse nuevamente en la clase. Haciendo así que la interfaz sea redundante. Simplemente se siente sintáctico ... bueno, basura para mí (Por favor, no te ofendas. Basura como en cosas inútiles).
En el ejemplo que se muestra a continuación, tomado de un hilo de interfaces de C # diferente en el desbordamiento de la pila, simplemente crearía una clase base llamada Pizza en lugar de una interfaz.
ejemplo sencillo (tomado de una contribución de desbordamiento de pila diferente)
public interface IPizza
{
public void Order();
}
public class PepperoniPizza : IPizza
{
public void Order()
{
//Order Pepperoni pizza
}
}
public class HawaiiPizza : IPizza
{
public void Order()
{
//Order HawaiiPizza
}
}
struct
tipos.Respuestas:
El punto es que la interfaz representa un contrato . Un conjunto de métodos públicos que cualquier clase de implementación debe tener. Técnicamente, la interfaz solo gobierna la sintaxis, es decir, qué métodos hay, qué argumentos obtienen y qué devuelven. Por lo general, también encapsulan la semántica, aunque eso solo por documentación.
Luego puede tener diferentes implementaciones de una interfaz y cambiarlas a voluntad. En su ejemplo, dado que cada instancia de pizza es una
IPizza
, puede usarlaIPizza
donde sea que maneje una instancia de un tipo de pizza desconocido. SeIPizza
garantiza que cualquier instancia cuyo tipo hereda es ordenable, ya que tiene unOrder()
método.Python no está estáticamente tipado, por lo tanto, los tipos se guardan y se buscan en tiempo de ejecución. Por lo tanto, puede intentar llamar a un
Order()
método en cualquier objeto. El tiempo de ejecución es feliz siempre que el objeto tenga dicho método y probablemente solo se encoja de hombros y diga »Meh.« Si no lo tiene. No es así en C #. El compilador es responsable de hacer las llamadas correctas y si solo tiene algo aleatorio,object
el compilador aún no sabe si la instancia durante el tiempo de ejecución tendrá ese método. Desde el punto de vista del compilador no es válido ya que no puede verificarlo. (Puede hacer tales cosas con reflexión o con ladynamic
palabra clave, pero eso está yendo un poco lejos en este momento, supongo).También tenga en cuenta que una interfaz en el sentido habitual no necesariamente tiene que ser un C #
interface
, también podría ser una clase abstracta o incluso una clase normal (que puede ser útil si todas las subclases necesitan compartir algún código común, en la mayoría de los casos , sin embargo, esinterface
suficiente).fuente
foo
implementosIWidget
, entonces un programador que vea una llamadafoo.woozle()
puede mirar la documentaciónIWidget
y saber qué se supone que debe hacer ese método . Es posible que el programador no tenga forma de saber de dónde vendrá el código para la implementación real, pero cualquier tipo que cumpla con elIWidget
contrato de interfaz se implementaráfoo
de manera consistente con ese contrato. En un lenguaje dinámico, por el contrario, no habría un punto de referencia claro de lo quefoo.woozle()
debería significar.Nadie realmente ha explicado en términos simples cómo las interfaces son útiles, así que voy a intentarlo (y robaré un poco la idea de la respuesta de Shamim).
Tomemos la idea de un servicio de pedido de pizza. Puede tener varios tipos de pizzas y una acción común para cada pizza es preparar el pedido en el sistema. Cada pizza tiene que prepararse, pero cada pizza se prepara de manera diferente . Por ejemplo, cuando se ordena una pizza de masa rellena, el sistema probablemente tiene que verificar que ciertos ingredientes estén disponibles en el restaurante y dejar de lado aquellos que no son necesarios para las pizzas de plato hondo.
Al escribir esto en código, técnicamente podrías simplemente hacer
Sin embargo, las pizzas de plato hondo (en términos de C #) pueden requerir diferentes propiedades para establecer
Prepare()
método que la corteza rellena, y por lo tanto terminas con muchas propiedades opcionales, y la clase no escala bien (¿qué pasa si agregas nuevas tipos de pizza).La forma correcta de resolver esto es usar la interfaz. La interfaz declara que todas las pizzas se pueden preparar, pero cada pizza se puede preparar de manera diferente. Entonces, si tiene las siguientes interfaces:
Ahora su código de manejo de pedidos no necesita saber exactamente qué tipos de pizzas se ordenaron para manejar los ingredientes. Solo tiene:
A pesar de que cada tipo de pizza se prepara de manera diferente, esta parte del código no tiene que preocuparse por el tipo de pizza con la que estamos tratando, solo sabe que se está pidiendo pizzas y, por lo tanto, cada llamada a
Prepare
preparará automáticamente cada pizza correctamente según su tipo, incluso si la colección tiene varios tipos de pizzas.fuente
public
. Entonces, dentro de la interfaz debería ser solovoid Prepare();
Para mí, al comenzar, el punto a estos solo se hizo claro cuando dejas de verlos como cosas para hacer que tu código sea más fácil / rápido de escribir, este no es su propósito. Tienen varios usos:
(Esto va a perder la analogía de la pizza, ya que no es muy fácil visualizar el uso de esto)
Digamos que estás haciendo un juego simple en la pantalla y tendrá criaturas con las que interactúas.
R: Pueden hacer que su código sea más fácil de mantener en el futuro al introducir un acoplamiento suelto entre su front-end y su implementación de back-end.
Para empezar, podría escribir esto, ya que solo habrá trolls:
Interfaz:
Dos semanas después, el departamento de marketing decide que también necesita Orcos, ya que leyeron sobre ellos en Twitter, por lo que tendría que hacer algo como:
Interfaz:
Y puedes ver cómo esto comienza a complicarse. Puede usar una interfaz aquí para que su front-end se escriba una vez y (aquí está el bit importante) probado, y luego puede conectar más elementos de back-end según sea necesario:
El extremo frontal es entonces:
El front end ahora solo se preocupa por la interfaz ICreature: no le preocupa la implementación interna de un troll o un orco, sino solo el hecho de que implementan ICreature.
Un punto importante a tener en cuenta al mirar esto desde este punto de vista es que también podrías haber usado fácilmente una clase de criatura abstracta, y desde esta perspectiva, esto tiene el mismo efecto.
Y podría extraer la creación a una fábrica:
Y nuestro front end se convertiría en:
El front end ahora ni siquiera tiene que tener una referencia a la biblioteca donde se implementan Troll y Orc (siempre que la fábrica esté en una biblioteca separada); no necesita saber nada de ellos.
B: Digamos que tiene una funcionalidad que solo algunas criaturas tendrán en su estructura de datos homogénea , por ejemplo
El front end podría ser:
C: uso para inyección de dependencia
La mayoría de los marcos de inyección de dependencia son más fáciles de trabajar cuando hay un acoplamiento muy flojo entre el código de front-end y la implementación de back-end. Si tomamos nuestro ejemplo de fábrica anterior y hacemos que nuestra fábrica implemente una interfaz:
Nuestro front end podría entonces tener esto inyectado (por ejemplo, un controlador MVC API) a través del constructor (típicamente):
Con nuestro marco DI (por ejemplo, Ninject o Autofac), podemos configurarlos para que en tiempo de ejecución se cree una instancia de CreatureFactory siempre que se necesite un ICreatureFactory en un constructor; esto hace que nuestro código sea agradable y simple.
También significa que cuando escribimos una prueba unitaria para nuestro controlador, podemos proporcionar una ICreatureFactory simulada (por ejemplo, si la implementación concreta requiere acceso a la base de datos, no queremos que nuestras pruebas unitarias dependan de eso) y probar fácilmente el código en nuestro controlador .
D: Hay otros usos, por ejemplo, tiene dos proyectos A y B que por razones de 'legado' no están bien estructurados, y A tiene una referencia a B.
Luego encontrará funcionalidad en B que necesita llamar a un método que ya está en A. No puede hacerlo utilizando implementaciones concretas a medida que obtiene una referencia circular.
Puede tener una interfaz declarada en B que la clase en A luego implementa. Su método en B puede pasar una instancia de una clase que implementa la interfaz sin problemas, incluso si el objeto concreto es de un tipo en A.
fuente
Aquí están sus ejemplos reexplicados:
fuente
Los ejemplos anteriores no tienen mucho sentido. Puede realizar todos los ejemplos anteriores utilizando clases (clase abstracta si desea que se comporte solo como un contrato ):
Obtiene el mismo comportamiento que con la interfaz. Puede crear
List<Food>
ay repetir eso sin saber qué clase se encuentra en la parte superior.Un ejemplo más adecuado sería la herencia múltiple:
Luego puede usarlos todos
MenuItem
y no preocuparse por cómo manejan cada llamada al método.fuente
Explicación simple con analogía
El problema a resolver: ¿Cuál es el propósito del polimorfismo?
Analogía: Así que soy el encargado de una obra de construcción.
Los comerciantes caminan por el sitio de construcción todo el tiempo. No sé quién va a cruzar esas puertas. Pero básicamente les digo qué hacer.
El problema con el enfoque anterior es que tengo que: (i) saber quién entra por esa puerta y, según quién sea, tengo que decirles qué hacer. Eso significa que tengo que saber todo sobre un comercio en particular. Hay costos / beneficios asociados con este enfoque:
Las implicaciones de saber qué hacer:
Esto significa que si el código del carpintero cambia de:
BuildScaffolding()
aBuildScaffold()
(es decir, un ligero cambio de nombre), también tendré que cambiar la clase de llamada (es decir, laForeperson
clase), tendrá que hacer dos cambios en el código en lugar de (básicamente ) solo uno. Con el polimorfismo, (básicamente) solo necesita hacer un cambio para lograr el mismo resultado.En segundo lugar, no tendrás que preguntar constantemente: ¿quién eres? ok haz esto ... ¿quién eres? ok haz eso ... polimorfismo - SECA ese código, y es muy efectivo en ciertas situaciones:
Con polimorfismo puede agregar fácilmente clases adicionales de comerciantes sin cambiar ningún código existente. (es decir, el segundo de los principios de diseño SÓLIDO: principio de apertura-cierre).
La solución
Imagine un escenario en el que, sin importar quién entra por la puerta, puedo decir: "Trabajar ()" y hacen sus respetuosos trabajos en los que se especializan: el plomero se ocuparía de las tuberías y el electricista se ocuparía de los cables.
El beneficio de este enfoque es que: (i) No necesito saber exactamente quién está entrando por esa puerta; todo lo que necesito saber es que serán un tipo de persona y que pueden trabajar, y en segundo lugar , (ii) no necesito saber nada sobre ese comercio en particular. El tradie se encargará de eso.
Entonces, en lugar de esto:
Puedo hacer algo como esto:
Cual es el beneficio?
El beneficio es que si cambian los requisitos de trabajo específicos del carpintero, etc., el capataz no necesitará cambiar su código, no necesita saberlo ni preocuparse. Lo único que importa es que el carpintero sepa lo que se entiende por trabajo (). En segundo lugar, si un nuevo tipo de trabajador de la construcción ingresa al lugar de trabajo, entonces el capataz no necesita saber nada sobre el oficio; todo lo que le importa es si el trabajador de la construcción (.eg Welder, Glazier, Tiler, etc.) puede hacer un poco de trabajo ().
Problema ilustrado y solución (con y sin interfaces):
Sin interfaz (Ejemplo 1):
Sin interfaz (Ejemplo 2):
Con una interfaz:
Resumen
Una interfaz le permite hacer que la persona haga el trabajo que se le asigna, sin que usted sepa exactamente quiénes son o los detalles de lo que pueden hacer. Esto le permite agregar fácilmente nuevos tipos (de comercio) sin cambiar su código existente (bueno, técnicamente lo cambia un poquito), y ese es el beneficio real de un enfoque OOP frente a una metodología de programación más funcional.
Si no comprende nada de lo anterior o si no está claro, pregunte en un comentario e intentaré mejorar la respuesta.
fuente
En ausencia de pato escribiendo como puede usarlo en Python, C # se basa en interfaces para proporcionar abstracciones. Si las dependencias de una clase fueran todos tipos concretos, no podría pasar ningún otro tipo; utilizando interfaces, puede pasar cualquier tipo que implemente la interfaz.
fuente
El ejemplo de Pizza es malo porque deberías estar usando una clase abstracta que maneja los pedidos, y las pizzas deberían anular el tipo de pizza, por ejemplo.
Usas interfaces cuando tienes una propiedad compartida, pero tus clases heredan de diferentes lugares, o cuando no tienes ningún código común que puedas usar. Por ejemplo, se usan cosas que se pueden eliminar
IDisposable
, sabes que se eliminará, simplemente no sabes qué sucederá cuando se elimine.Una interfaz es solo un contrato que le dice algunas cosas que puede hacer un objeto, qué parámetros y qué tipos de retorno esperar.
fuente
Considere el caso en el que no controla ni posee las clases base.
Tome los controles visuales, por ejemplo, en .NET para Winforms, todos ellos heredan del control de clase base, que está completamente definido en el marco .NET.
Supongamos que está en el negocio de crear controles personalizados. Desea crear nuevos botones, cuadros de texto, vistas de lista, cuadrículas, etc., y desea que todos tengan ciertas características exclusivas de su conjunto de controles.
Por ejemplo, es posible que desee una forma común de manejar la temática o una forma común de manejar la localización.
En este caso, no puede "simplemente crear una clase base" porque si lo hace, debe volver a implementar todo lo relacionado con los controles.
En su lugar, descenderá de Button, TextBox, ListView, GridView, etc. y agregará su código.
Pero esto plantea un problema, ¿cómo puede ahora identificar qué controles son "suyos", cómo puede crear un código que diga "para todos los controles en el formulario que son míos, establezca el tema en X".
Ingresar interfaces.
Las interfaces son una forma de mirar un objeto, para determinar que el objeto se adhiere a un determinado contrato.
Crearía "YourButton", descendería de Button y agregaría soporte para todas las interfaces que necesita.
Esto le permitiría escribir código como el siguiente:
Esto no sería posible sin interfaces, sino que tendría que escribir código como este:
fuente
En este caso, podría (y probablemente lo haría) simplemente definir una clase base de Pizza y heredar de ellos. Sin embargo, hay dos razones por las cuales las interfaces le permiten hacer cosas que no se pueden lograr de otras maneras:
Una clase puede implementar múltiples interfaces. Simplemente define las características que debe tener la clase. Implementar una gama de interfaces significa que una clase puede cumplir múltiples funciones en diferentes lugares.
Una interfaz se puede definir en un ámbito más amplio que la clase o la persona que llama. Esto significa que puede separar la funcionalidad, separar la dependencia del proyecto y mantener la funcionalidad en un proyecto o clase, y la implementación de esto en otro lugar.
Una implicación de 2 es que puede cambiar la clase que se está utilizando, simplemente requiriendo que implemente la interfaz adecuada.
fuente
Considere que no puede usar la herencia múltiple en C # y luego vuelva a mirar su pregunta.
fuente
Interfaz = contrato, usado para acoplamiento flojo (ver GRASP ).
fuente
Si estoy trabajando en una API para dibujar formas, es posible que quiera usar DirectX o llamadas gráficas, o OpenGL. Entonces, crearé una interfaz, que abstraerá mi implementación de lo que llamas.
Así que llama a un método de fábrica:
MyInterface i = MyGraphics.getInstance()
. Luego, tiene un contrato, para saber en qué funciones puede esperarMyInterface
. Entonces, puedes llamari.drawRectangle
oi.drawCube
y saber que si intercambia una biblioteca por otra, las funciones son compatibles.Esto se vuelve más importante si está utilizando la Inyección de dependencias, ya que puede, en un archivo XML, intercambiar implementaciones.
Entonces, puede tener una biblioteca de cifrado que se puede exportar para uso general, y otra que está a la venta solo para empresas estadounidenses, y la diferencia está en que cambia un archivo de configuración y el resto del programa no cambiado
Esto se usa mucho con colecciones en .NET, ya que solo debe usar, por ejemplo,
List
variables, y no se preocupe si era una ArrayList o LinkedList.Mientras codifique en la interfaz, el desarrollador puede cambiar la implementación real y el resto del programa no se modifica.
Esto también es útil cuando se realizan pruebas unitarias, ya que puede simular interfaces completas, por lo tanto, no tengo que ir a una base de datos, sino a una implementación simulada que solo devuelve datos estáticos, por lo que puedo probar mi método sin preocuparme si la base de datos está inactiva por mantenimiento o no.
fuente
Una interfaz es realmente un contrato que las clases implementadoras deben seguir, de hecho, es la base de casi todos los patrones de diseño que conozco.
En su ejemplo, la interfaz se crea porque entonces todo lo que ES una pizza, lo que significa que implementa la interfaz de Pizza, se garantiza que se ha implementado
Después de su código mencionado, podría tener algo como esto:
De esta manera, está utilizando el polimorfismo y lo único que le importa es que sus objetos respondan al orden ().
fuente
Hice una búsqueda de la palabra "composición" en esta página y no la vi ni una vez. Esta respuesta es muy adicional a las respuestas mencionadas anteriormente.
Una de las razones absolutamente cruciales para usar interfaces en un proyecto orientado a objetos es que le permiten favorecer la composición sobre la herencia. Al implementar interfaces, puede desacoplar sus implementaciones de los diversos algoritmos que está aplicando a ellas.
Este excelente tutorial de "Patrón de decorador" de Derek Banas (que, curiosamente, también usa pizza como ejemplo) es una ilustración que vale la pena:
https://www.youtube.com/watch?v=j40kRwSm4VE
fuente
Las interfaces son para aplicar la conexión entre diferentes clases. por ejemplo, tienes una clase para auto y un árbol;
desea agregar una funcionalidad grabable para ambas clases. Pero cada clase tiene sus propias formas de quemar. entonces simplemente haces;
fuente
Obtendrá interfaces, cuando las necesite :) Puede estudiar ejemplos, pero necesita ¡Ajá! efecto para realmente conseguirlos.
Ahora que sabe qué son las interfaces, simplemente codifique sin ellas. Tarde o temprano se encontrará con un problema, donde el uso de interfaces será lo más natural.
fuente
Me sorprende que no muchas publicaciones contengan la razón más importante para una interfaz: patrones de diseño . Es la imagen más amplia en el uso de contratos, y aunque es una decoración de sintaxis para el código de máquina (para ser sincero, el compilador probablemente simplemente los ignora), la abstracción y las interfaces son fundamentales para la POO, la comprensión humana y las arquitecturas de sistemas complejos.
Expandamos la analogía de la pizza para decir una comida completa de 3 platos. Todavía tendremos la
Prepare()
interfaz principal para todas nuestras categorías de alimentos, pero también tendremos declaraciones abstractas para las selecciones de cursos (entrante, principal, postre) y diferentes propiedades para los tipos de alimentos (salados / dulces, vegetarianos / no vegetarianos, sin gluten, etc.).Con base en estas especificaciones, podríamos implementar el patrón Abstract Factory para conceptualizar todo el proceso, pero usar interfaces para asegurar que solo los cimientos sean concretos. Todo lo demás podría volverse flexible o alentar el polimorfismo, pero mantener la encapsulación entre las diferentes clases
Course
que implementan laICourse
interfaz.Si tuviera más tiempo, me gustaría elaborar un ejemplo completo de esto, o alguien puede extender esto por mí, pero en resumen, una interfaz C # sería la mejor herramienta para diseñar este tipo de sistema.
fuente
Aquí hay una interfaz para objetos que tienen una forma rectangular:
Todo lo que exige es que implemente formas de acceder al ancho y la altura del objeto.
Ahora definamos un método que funcione en cualquier objeto que sea
IRectangular
:Eso devolverá el área de cualquier objeto rectangular.
Implementemos una clase
SwimmingPool
que sea rectangular:Y otra clase
House
que también es rectangular:Dado eso, puede llamar al
Area
método en casas o piscinas:De esta manera, sus clases pueden "heredar" el comportamiento (métodos estáticos) de cualquier número de interfaces.
fuente
Una interfaz define un contrato entre el proveedor de una determinada funcionalidad y los consumidores correspondientes. Desacopla la implementación del contrato (interfaz). Debe echar un vistazo a la arquitectura y el diseño orientados a objetos. Es posible que desee comenzar con wikipedia: http://en.wikipedia.org/wiki/Interface_(computing)
fuente
Qué ?
Las interfaces son básicamente un contrato que todas las clases que implementan la interfaz deben seguir. Parecen una clase pero no tiene implementación.
En la
C#
interfaz, los nombres por convención se definen al prefijar una 'I', por lo que si desea tener una interfaz llamada formas, debe declararla comoIShapes
Ahora por qué ?
Improves code re-usability
Digamos que usted quiere dibujar
Circle
,Triangle.
puede agruparlos juntos y llamarlosShapes
y tienen métodos para dibujarCircle
yTriangle
Pero tener aplicación concreta sería una mala idea porque mañana es posible que decida tener 2 másShapes
Rectangle
ySquare
. Ahora, cuando los agrega, existe una gran posibilidad de que pueda romper otras partes de su código.Con Interface, aísla las diferentes implementaciones del Contrato
Escenario en vivo Día 1
Se te pidió que crearas una aplicación para dibujar círculos y triángulos
Escenario en vivo Día 2
Si se le solicitó agregar
Square
y agregarRectangle
, todo lo que tiene que hacer es crear la implementación para elloclass Square: IShapes
yMain
agregarlo a la listashapes.Add(new Square());
fuente
Aquí hay muchas buenas respuestas, pero me gustaría intentarlo desde una perspectiva ligeramente diferente.
Puede estar familiarizado con los principios SÓLIDOS del diseño orientado a objetos. En resumen:
S - Principio de responsabilidad única O - Principio abierto / cerrado L - Principio de sustitución de Liskov I - Principio de segregación de interfaz D - Principio de inversión de dependencia
Seguir los principios SÓLIDOS ayuda a producir código limpio, bien factorizado, cohesivo y poco acoplado. Dado que:
entonces cualquier cosa que ayude con la gestión de dependencias es una gran victoria. Las interfaces y el principio de inversión de dependencias realmente ayudan a desacoplar el código de las dependencias de clases concretas, por lo que el código puede escribirse y razonarse en términos de comportamientos en lugar de implementaciones. Esto ayuda a dividir el código en componentes que se pueden componer en tiempo de ejecución en lugar de en tiempo de compilación y también significa que esos componentes se pueden conectar y desconectar fácilmente sin tener que alterar el resto del código.
Las interfaces ayudan en particular con el Principio de Inversión de Dependencia, donde el código puede ser componente en una colección de servicios, y cada servicio es descrito por una interfaz. Los servicios se pueden "inyectar" en clases en tiempo de ejecución pasándolos como un parámetro constructor. Esta técnica realmente se vuelve crítica si comienzas a escribir pruebas unitarias y usas un desarrollo basado en pruebas. ¡Intentalo! Comprenderá rápidamente cómo las interfaces ayudan a separar el código en fragmentos manejables que se pueden probar individualmente de forma aislada.
fuente
El objetivo principal de las interfaces es que establece un contrato entre usted y cualquier otra clase que implemente esa interfaz, lo que hace que su código se desacople y permita la capacidad de expansión.
fuente
Therese se preguntan ejemplos realmente geniales.
Otro, en el caso de una declaración de cambio, ya no tiene la necesidad de mantener y cambiar cada vez que quiera que rio realice una tarea de una manera específica.
En su ejemplo de pizza, si desea hacer una pizza, la interfaz es todo lo que necesita, a partir de ahí cada pizza se encarga de su propia lógica.
Esto ayuda a reducir el acoplamiento y la complejidad ciclomática. Todavía tiene que implementar la lógica, pero habrá menos de lo que tenga que estar pendiente en la imagen más amplia.
Para cada pizza, puede realizar un seguimiento de la información específica de esa pizza. Lo que otras pizzas tienen no importa porque solo las otras pizzas necesitan saberlo.
fuente
La forma más sencilla de pensar en las interfaces es reconocer lo que significa herencia. Si la clase CC hereda la clase C, significa que:
Esas dos funciones de la herencia son, en cierto sentido, independientes; aunque la herencia se aplica a ambos simultáneamente, también es posible aplicar el segundo sin el primero. Esto es útil porque permitir que un objeto herede miembros de dos o más clases no relacionadas es mucho más complicado que permitir que un tipo de cosa sea sustituible por varios tipos.
Una interfaz es algo así como una clase base abstracta, pero con una diferencia clave: un objeto que hereda una clase base no puede heredar ninguna otra clase. Por el contrario, un objeto puede implementar una interfaz sin afectar su capacidad de heredar cualquier clase deseada o implementar cualquier otra interfaz.
Una buena característica de esto (infrautilizado en el marco .net, en mi humilde opinión) es que permiten indicar de manera declarativa las cosas que puede hacer un objeto. Algunos objetos, por ejemplo, querrán un objeto de fuente de datos del que puedan recuperar cosas por índice (como es posible con una Lista), pero no necesitarán almacenar nada allí. Otras rutinas necesitarán un objeto de depósito de datos donde puedan almacenar cosas no por índice (como con Collection.Add), pero no necesitarán leer nada. Algunos tipos de datos permitirán el acceso por índice, pero no permitirán la escritura; otros permitirán la escritura, pero no permitirán el acceso por índice. Algunos, por supuesto, permitirán ambos.
Si ReadableByIndex y Appendable fueran clases base no relacionadas, sería imposible definir un tipo que se pueda pasar tanto a las cosas que esperan un ReadableByIndex como a las cosas que esperan un Appendable. Uno podría intentar mitigar esto haciendo que ReadableByIndex o Appendable se deriven del otro; la clase derivada tendría que poner a disposición miembros públicos para ambos propósitos, pero advertir que algunos miembros públicos podrían no funcionar realmente. Algunas de las clases e interfaces de Microsoft hacen eso, pero eso es bastante desagradable. Un enfoque más limpio es tener interfaces para los diferentes propósitos, y luego hacer que los objetos implementen interfaces para las cosas que realmente pueden hacer. Si uno tuviera una interfaz IReadableByIndex y otra interfaz IAppendable,
fuente
Las interfaces también se pueden conectar en cadena para crear otra interfaz más. Esta capacidad para implementar múltiples interfaces le da al desarrollador la ventaja de agregar funcionalidad a sus clases sin tener que cambiar la funcionalidad de la clase actual (Principios SÓLIDOS)
O = "Las clases deben estar abiertas para extensión pero cerradas para modificación"
fuente
Para mí, una ventaja / beneficio de una interfaz es que es más flexible que una clase abstracta. Como solo puede heredar 1 clase abstracta pero puede implementar múltiples interfaces, los cambios en un sistema que hereda una clase abstracta en muchos lugares se vuelven problemáticos. Si se hereda en 100 lugares, un cambio requiere cambios en los 100. Pero, con la interfaz, puede colocar el nuevo cambio en una nueva interfaz y simplemente usar esa interfaz donde sea necesario (Seq. De interfaz de SOLID). Además, el uso de memoria parece que sería menor con la interfaz ya que un objeto en el ejemplo de interfaz se usa solo una vez en la memoria a pesar de cuántos lugares implementan la interfaz.
fuente
Las interfaces se utilizan para impulsar la coherencia, de una manera que está acoplada libremente, lo que la hace diferente a la clase abstracta que está estrechamente acoplada. Es por eso que también se define comúnmente como un contrato. Cuantas clases que implementen la interfaz cumplan con las "reglas / sintaxis" definido por la interfaz y no hay elementos concretos dentro de ella.
Solo daré un ejemplo respaldado por el gráfico a continuación.
Imagine que en una fábrica hay 3 tipos de máquinas: una máquina de rectángulo, una máquina de triángulo y una máquina de polígonos. Los tiempos son competitivos y desea optimizar la capacitación de los operadores. Solo desea capacitarlos en una metodología de arranque y parada de máquinas para que pueda tiene un botón de inicio verde y un botón de detención rojo. Así que ahora en 3 máquinas diferentes tiene una manera consistente de iniciar y detener 3 tipos diferentes de máquinas. Ahora imagine que estas máquinas son clases y las clases necesitan tener métodos de inicio y detención, cómo va a impulsar la coherencia entre estas clases, que puede ser muy diferente? La interfaz es la respuesta.
Un ejemplo simple para ayudarlo a visualizar, uno podría preguntarse ¿por qué no usar la clase abstracta? Con una interfaz, los objetos no tienen que estar directamente relacionados o heredados y aún puede generar consistencia en diferentes clases.
fuente
Permítanme describir esto desde una perspectiva diferente. Creemos una historia de acuerdo con el ejemplo que he mostrado anteriormente;
Program, Machine e IMachine son los actores de nuestra historia. El programa quiere ejecutarse pero no tiene esa habilidad y Machine sabe cómo ejecutarlo. Machine e IMachine son mejores amigos, pero el programa no está en términos de hablar con Machine. Entonces, Program e IMachine llegaron a un acuerdo y decidieron que IMachine le dirá a Program cómo ejecutar mirando la máquina (como un reflector).
Y el programa aprende a ejecutar con la ayuda de IMachine.
La interfaz proporciona comunicación y desarrolla proyectos sueltos.
PD: Tengo el método de clase concreta como privado. Mi objetivo aquí es lograr un acoplamiento flexible evitando el acceso a propiedades y métodos de clase concretos, y dejando solo la posibilidad de llegar a ellos a través de interfaces. (Entonces definí los métodos de las interfaces explícitamente).
fuente
Sé que llego muy tarde ... (casi nueve años), pero si alguien quiere una pequeña explicación, puedes ir por esto:
En palabras simples, utiliza la Interfaz cuando sabe lo que puede hacer un Objeto o qué función vamos a implementar en un objeto. Ejemplo Insertar, Actualizar y Eliminar.
Nota importante: las interfaces son SIEMPRE públicas.
Espero que esto ayude.
fuente