He estado estudiando y codificando en C # por algún tiempo. Pero aún así, no puedo entender la utilidad de las interfaces. Traen muy poco a la mesa. Aparte de proporcionar las firmas de función, no hacen nada. Si puedo recordar los nombres y la firma de las funciones que se necesitan para implementar, no hay necesidad de ellas. Están allí solo para asegurarse de que dichas funciones (en la interfaz) se implementen en la clase heredada.
C # es un gran lenguaje, pero a veces le da la sensación de que primero Microsoft crea el problema (no permite la herencia múltiple) y luego proporciona la solución, que es bastante tediosa.
Esa es mi comprensión, que se basa en una experiencia de codificación limitada. ¿Cuál es tu opinión sobre las interfaces? ¿Con qué frecuencia los usas y qué te hace hacerlo?
fuente
Respuestas:
Correcto. Ese es un beneficio suficientemente impresionante para justificar la función. Como han dicho otros, una interfaz es una obligación contractual de implementar ciertos métodos, propiedades y eventos. El beneficio convincente de un lenguaje de tipo estático es que el compilador puede verificar que se cumpla realmente un contrato en el que se basa su código.
Dicho esto, las interfaces son una forma bastante débil de representar obligaciones contractuales. Si desea una forma más sólida y flexible de representar las obligaciones contractuales, consulte la función Contratos de código que se incluye con la última versión de Visual Studio.
Bueno, me alegra que te guste.
Todos los diseños de software complejos son el resultado de sopesar las características en conflicto entre sí y de tratar de encontrar el "punto óptimo" que brinde grandes beneficios por pequeños costos. A través de una experiencia dolorosa, hemos aprendido que los lenguajes que permiten la herencia múltiple con el propósito de compartir la implementación tienen beneficios relativamente pequeños y costos relativamente altos. Permitir la herencia múltiple solo en las interfaces, que no comparten detalles de implementación, brinda muchos de los beneficios de la herencia múltiple sin la mayoría de los costos.
fuente
Assume
llamadas, para casos como miembros de matriz o enumeración. Después de agregar todo y ver el desorden estáticamente verificado que tuve, volví al control de la fuente porque redujo la calidad de mi proyecto.Entonces, en este ejemplo, el PowerSocket no sabe nada más sobre los otros objetos. Todos los objetos dependen de la energía proporcionada por el PowerSocket, por lo que implementan IPowerPlug y, al hacerlo, pueden conectarse a él.
Las interfaces son útiles porque proporcionan contratos que los objetos pueden usar para trabajar juntos sin necesidad de saber nada más el uno del otro.
fuente
El objetivo de las interfaces no es ayudarlo a recordar qué método implementar, está aquí para definir un contrato . En foreach P.Brian.Mackey ejemplo (que resulta ser incorrecto , pero no nos importa), IEnumerable define un contrato entre foreach y cualquier cosa enumerable. Dice: "Quienquiera que sea, siempre que cumpla con el contrato (implemente IEnumerable), le prometo que iteraré sobre todos sus elementos". Y eso es genial (para un lenguaje no dinámico).
Gracias a las interfaces, puede lograr un acoplamiento muy bajo entre dos clases.
fuente
Las interfaces son la mejor manera de mantener construcciones bien desacopladas.
Al escribir pruebas, encontrará que las clases concretas no funcionarán en su entorno de prueba.
Ejemplo: desea probar una clase que depende de una clase de servicio de acceso a datos . Si esa clase está hablando con un servicio web o una base de datos, su prueba unitaria no se ejecutará en su entorno de prueba (además se ha convertido en una prueba de integración).
¿Solución? Use una interfaz para su servicio de acceso a datos y simule esa interfaz para que pueda probar su clase como una unidad.
Por otro lado, WPF y Silverlight no juegan en absoluto con las interfaces cuando se trata de encuadernación. Esta es una arruga bastante desagradable.
fuente
¡Las interfaces son la columna vertebral del polimorfismo (estático)! La interfaz es lo que importa. La herencia no funcionaría sin interfaces, ya que las subclases básicamente heredan la interfaz ya implementada del padre.
Muy a menudo. Todo lo que necesita ser conectable es una interfaz en mis aplicaciones. Muchas veces tiene clases no relacionadas que necesitan proporcionar el mismo comportamiento. No puede resolver tales problemas con la herencia.
¿Necesita diferentes algoritmos para realizar operaciones con los mismos datos? ¡Use una interfaz ( vea el patrón de estrategia )!
¿Quieres usar diferentes implementaciones de listas? Código contra una interfaz y la persona que llama no necesita preocuparse por la implementación.
Se ha considerado una buena práctica (no solo en OOP) codificar contra interfaces por años, por una sola razón: es fácil cambiar una implementación cuando te das cuenta de que no se ajusta a tus necesidades. Es bastante engorroso si intenta lograrlo solo con herencia múltiple o se reduce a crear clases vacías para proporcionar la interfaz necesaria.
fuente
Probablemente lo haya usado
foreach
y lo haya encontrado como una herramienta de iteración bastante útil. ¿Sabía que requiere una interfaz para funcionar, IEnumerable ?Ese es ciertamente un caso concreto que habla de la utilidad de una interfaz.
fuente
Las interfaces son para codificar objetos como un enchufe para el cableado doméstico. ¿Soldarías tu radio directamente al cableado de tu casa? ¿Qué tal tu aspiradora? Por supuesto no. El enchufe y la toma de corriente en la que encaja forman la "interfaz" entre el cableado de su casa y el dispositivo que necesita energía. El cableado de su casa no necesita saber nada sobre el dispositivo, aparte de que utiliza un enchufe con conexión a tierra de tres terminales y requiere energía eléctrica a 120 VCA <= 15A. Por el contrario, el dispositivo no requiere un conocimiento arcano de cómo está conectada su casa, además de que tiene una o más salidas de tres clavijas convenientemente ubicadas que proporcionan 120VCA <= 15A.
Las interfaces realizan una función muy similar en el código. Un objeto puede declarar que una variable particular, parámetro o tipo de retorno es de un tipo de interfaz. La interfaz no se puede instanciar directamente con una
new
palabra clave, pero mi objeto puede recibir o encontrar la implementación de esa interfaz con la que tendrá que trabajar. Una vez que el objeto tiene su dependencia, no tiene que saber exactamente cuál es esa dependencia, solo tiene que saber que puede llamar a los métodos X, Y y Z en la dependencia. Las implementaciones de la interfaz no tienen que saber cómo se utilizarán, solo deben saber que se espera que proporcionen los métodos X, Y y Z con firmas particulares.Por lo tanto, al abstraer varios objetos detrás de la misma interfaz, proporciona un conjunto común de funcionalidades a cualquier consumidor de objetos de esa interfaz. No tiene que saber que el objeto es, por ejemplo, una Lista, un Diccionario, una Lista enlazada, una Lista ordenada o lo que sea. Como sabe que todos estos son IEnumerables, puede usar los métodos de IEnumerable para revisar cada elemento de estas colecciones de uno en uno. No tiene que saber que una clase de salida es ConsoleWriter, FileWriter, NetworkStreamWriter o incluso un MulticastWriter que toma otros tipos de escritores; todo lo que tiene que saber es que son todos IWriters (o lo que sea), y por lo tanto tienen un método de "Escritura" en el que puede pasar una cadena, y esa cadena se generará.
fuente
Si bien es claramente un placer para el programador (al principio, al menos) tener herencia múltiple, esta es una omisión casi trivial, y usted (en la mayoría de los casos) no debe confiar en la herencia múltiple. Las razones para esto son complejas, pero si realmente quieres aprender al respecto, considera la experiencia de los dos lenguajes de programación más famosos (según el índice TIOBE ) que lo admiten: C ++ y Python (3º y 8º respetablemente).
En Python, se admite la herencia múltiple, pero los programadores la malinterpretan casi universalmente y decir que usted sabe cómo funciona significa leer y comprender este documento sobre el tema: Orden de resolución de métodos . Algo más, que sucedió en Python, es que las interfaces se introdujeron en el lenguaje: Zope.Interfaces.
Para C ++, busque en Google "Jerarquía de diamantes C ++" y contemple la fealdad que está a punto de cubrirlo. Los profesionales de C ++ saben cómo usar la herencia múltiple. Todos los demás generalmente solo juegan sin saber cuáles serán los resultados. Otra cosa que muestra cuán útiles son las interfaces es el hecho de que, en muchos casos, una clase podría necesitar anular completamente el comportamiento de sus padres. En tales casos, la implementación primaria es innecesaria y solo carga a la clase secundaria con la memoria para las variables privadas de la matriz, lo que puede no importar en la era de C #, pero es importante cuando se realiza una programación integrada. Si usa una interfaz, ese problema es inexistente.
En conclusión, las interfaces son, en mi opinión, una parte esencial de OOP, porque hacen cumplir un contrato. La herencia múltiple es útil en casos limitados, y generalmente solo para hombres que saben cómo usarla. Entonces, si eres un principiante, eres el que es tratado por la falta de herencia múltiple; esto te da una mejor oportunidad de no cometer un error .
Además, históricamente, la idea de una interfaz se basa mucho antes que las especificaciones de diseño C # de Microsoft. La mayoría de las personas consideran que C # es una actualización sobre Java (en la mayoría de los sentidos), y adivinan de dónde obtuvo C # sus interfaces: Java. Protocolo es una palabra más antigua para el mismo concepto, y es mucho más antiguo que .NET.
Actualización: Ahora veo que podría haber respondido una pregunta diferente: por qué las interfaces en lugar de herencia múltiple, pero esta parecía ser la respuesta que estabas buscando. Además, un lenguaje OO debe tener al menos uno de los dos, y las otras respuestas han cubierto su pregunta original.
fuente
Me resulta difícil imaginar un código C # limpio y orientado a objetos sin el uso de interfaces. Los usa siempre que desee imponer la disponibilidad de ciertas funciones sin obligar a las clases a heredar de una clase base específica, y esto permite que su código tenga el nivel relevante de acoplamiento (bajo).
No estoy de acuerdo con que la herencia múltiple sea mejor que tener interfaces, incluso antes de llegar a argumentar que la herencia múltiple viene con su propio conjunto de dolores. Las interfaces son una herramienta básica para habilitar el polimorfismo y la reutilización de código, ¿qué más se necesita?
fuente
Personalmente, amo la clase abstracta y la uso más que una interfaz. La principal diferencia viene con la integración con interfaces .NET como IDisposable, IEnumerable, etc. ... y con interoperabilidad COM. Además, la interfaz requiere un poco menos de esfuerzo para escribir que una clase abstracta, y una clase puede implementar más de una interfaz mientras que solo puede heredar de una clase.
Dicho esto, creo que la mayoría de las cosas para las que usaría una interfaz están mejor atendidas por una clase abstracta. Las funciones virtuales puras (funciones abstractas) le permiten obligar a un implementador a definir una función similar a la forma en que una interfaz obliga a un implementador a definir a todos sus miembros.
Sin embargo, normalmente usa una interfaz cuando no desea imponer un cierto diseño a la superclase, mientras que usaría una clase abstracta para tener un diseño reutilizable que ya esté implementado en su mayoría.
He usado interfaces extensamente con entornos de plugins de escritura usando el espacio de nombres System.ComponentModel. Son bastante útiles.
fuente
Puedo decir que me relaciono con eso. Cuando comencé a aprender sobre OO y C #, tampoco obtuve interfaces. Está bien. Solo necesitamos encontrar algo que lo haga apreciar las conveniencias de las interfaces.
Déjame probar dos enfoques. Y perdóname por las generalizaciones.
Prueba 1
Digamos que eres un hablante nativo de inglés. Vas a otro país donde el inglés no es el idioma nativo. Necesitas ayuda. Necesitas a alguien que pueda ayudarte.
¿Pregunta: "Hey, naciste en los Estados Unidos?" Esto es herencia.
¿O preguntas: "Oye, hablas inglés"? Esta es la interfaz.
Si le importa lo que hace, puede confiar en las interfaces. Si te importa lo que es, confías en la herencia.
Está bien confiar en la herencia. Si necesita a alguien que hable inglés, le guste el té y le guste el fútbol, es mejor que solicite un británico. :)
Prueba 2
Ok, intentemos con otro ejemplo.
Utiliza diferentes bases de datos y necesita implementar clases abstractas para trabajar con ellas. Pasará su clase a alguna clase del proveedor de DB.
¿Herencia múltiple, dices? Intenta eso con el caso anterior. No puedes El compilador no sabrá a qué método de Connect está intentando llamar.
Ahora, hay algo con lo que podemos trabajar, al menos en C #, donde podemos implementar interfaces explícitamente.
Conclusión
Los ejemplos no son los mejores, pero creo que se entiende.
Solo "obtendrá" interfaces cuando sienta la necesidad de ellas. Hasta que pienses que no son para ti.
fuente
Hay 2 razones principales:
fuente
El uso de interfaces ayuda a que el sistema permanezca desacoplado y, por lo tanto, sea más fácil de refactorizar, cambiar y volver a implementar. Es un concepto muy básico para la ortodoxia orientada a objetos y aprendí por primera vez cuando los gurús de C ++ crearon "clases abstractas puras" que son bastante equivalentes a las interfaces.
fuente
Las interfaces en sí mismas no son muy útiles. Pero cuando lo implementan clases concretas, ve que le brinda la flexibilidad de tener una o más implementaciones. La ventaja es que el objeto que usa la interfaz no necesita saber cómo van los detalles de la implementación real, eso se llama encapsulación.
fuente
Se utilizan principalmente para la reutilización de código. Si codifica para la interfaz, puede usar una clase diferente que herede de esa interfaz y no romper todo.
También son muy útiles en los servicios web en los que desea que el cliente sepa lo que hace una clase (para que puedan consumirla) pero no desea darles el código real.
fuente
Como programador / desarrollador joven, solo aprendiendo C # es posible que no vea la utilidad de la interfaz, porque puede escribir sus códigos usando sus clases y el código funciona bien, pero en el escenario de la vida real, construir una aplicación escalable, robusta y mantenible implica usar algunos arquitectónicos y patrones, que solo pueden hacerse posibles mediante el uso de la interfaz, por ejemplo, en la inyección de dependencia.
fuente
Una implementación del mundo real:
Puede lanzar un objeto como el tipo de interfaz:
Puedes crear una lista de una interfaz
Con estos objetos puede acceder a cualquiera de los métodos o propiedades de la interfaz. De esta manera, puede definir una interfaz para su parte de un programa. Y construye la lógica a su alrededor. Entonces alguien más puede implementar su interfaz en sus objetos de negocios. Si los BO cambian, pueden cambiar la lógica de los componentes de la interfaz y no requieren un cambio en la lógica de su pieza.
fuente
Las interfaces se prestan a la modularidad de estilo de complemento al proporcionar un mecanismo para que las clases comprendan (y se suscriban) a ciertos tipos de mensajes que entrega su sistema. Lo elaboraré.
En su aplicación, usted decide que cada vez que se carga o recarga un formulario, desea que se borren todas las cosas que alberga. Usted define una
IClear
interfaz que implementaClear
. Además, usted decide que cada vez que el usuario presiona el botón Guardar, el formulario debe intentar mantener su estado. Por lo tanto, todo lo que cumpleISave
recibe un mensaje para persistir en su estado. Por supuesto, prácticamente hablando, la mayoría de las interfaces manejan varios mensajes.Lo que distingue a las interfaces es que se puede lograr un comportamiento común sin herencia. La clase que implementa una interfaz dada simplemente comprende cómo comportarse cuando se emite un comando (un mensaje de comando) o cómo responder cuando se le consulta (un mensaje de consulta). Esencialmente, las clases en su aplicación entienden los mensajes que proporciona su aplicación. Esto facilita la construcción de un sistema modular en el que las cosas se pueden conectar.
En la mayoría de los lenguajes existen mecanismos (como LINQ ) para consultar cosas que cumplen con una interfaz. Esto generalmente lo ayudará a eliminar la lógica condicional porque no tendrá que decir cosas diferentes (que no son necesariamente derivadas de la misma cadena de herencia) cómo comportarse de manera similar (de acuerdo con un mensaje en particular). En su lugar, reúne todo lo que comprende un determinado mensaje (se rige por una interfaz) y publica el mensaje.
Por ejemplo, podría reemplazar ...
...con:
Que efectivamente se parece mucho a:
De esta manera, podemos evitar programáticamente decirle a cada cosa que se limpie. Y cuando se agregan elementos limpiables en el futuro, simplemente responden sin ningún código adicional.
fuente
El siguiente es pseudocódigo:
Las últimas clases pueden ser implementaciones completamente diferentes.
A menos que sea posible la herencia múltiple, la herencia impone la implementación de la clase padre haciendo las cosas más rígidas. La programación contra interfaces, por otro lado, puede permitir que su código o marco sea extremadamente flexible. Si alguna vez encuentras un caso en el que deseaste poder cambiar de clase en una cadena de herencia, entenderás por qué.
Por ejemplo, un marco que proporciona un lector originalmente destinado a leer datos del disco podría volver a implementarse para hacer algo de la misma naturaleza pero de una manera totalmente diferente. Como interpretar el código Morse, por ejemplo.
fuente