Estoy en un punto en mi aprendizaje de desarrollo donde siento que debo aprender más sobre las interfaces.
Frecuentemente leo sobre ellos, pero parece que no puedo entenderlos.
He leído ejemplos como: Clase base de animales, con una interfaz animal para cosas como 'Caminar', 'Correr', 'GetLegs', etc., pero nunca he estado trabajando en algo y me sentí como "Hey, debería usar una interfaz ¡aquí!"
¿Qué me estoy perdiendo? ¿Por qué es un concepto tan difícil de entender para mí? Me siento intimidado por el hecho de que tal vez nunca me dé cuenta de una necesidad concreta de uno, ¡principalmente debido a algún aspecto que falta para entenderlos! ¡Me hace sentir como si me faltara algo superior en términos de ser desarrollador! Si alguien ha tenido una experiencia como esta y ha tenido un gran avance, agradecería algunos consejos sobre cómo entender este concepto. Gracias.
fuente
Respuestas:
resuelve este problema concreto:
tienes a, b, c, d de 4 tipos diferentes. en todo tu código tienes algo como:
por qué no hacer que implementen IProcessable y luego
esto se escalará mucho mejor cuando agregue, digamos, 50 tipos de clases que hacen lo mismo.
Otro problema concreto:
¿Alguna vez has echado un vistazo a System.Linq.Enumerable? Define una tonelada de métodos de extensión que operan en cualquier tipo que implemente IEnumerable. Como todo lo que implementa IEnumerable básicamente dice "Apoyo la iteración en un patrón de tipo foreach desordenado", puede definir comportamientos complejos (Count, Max, Where, Select, etc.) para cualquier tipo enumerable.
fuente
foreach(IMyCompanyWidgetFrobber a in list) a.Frob(widget, context);
Me gusta mucho la respuesta de Jimmy, pero siento que necesito agregarle algo. La clave de todo es el "capaz" en IProcess capaz. Indica una capacidad (o propiedad, pero que significa "calidad intrínseca", no en el sentido de las propiedades de C #) del objeto que implementa la interfaz. IAnimal probablemente no sea un buen ejemplo para una interfaz, pero IWalkable podría ser una buena interfaz si su sistema tiene muchas cosas que pueden caminar. Es posible que tenga clases derivadas de animales como perro, vaca, pescado, serpiente. Los dos primeros probablemente implementarían IWalkable, los últimos dos no caminan, por lo que no lo harían. Ahora preguntas "¿por qué no simplemente tener otra superclase, WalkingAnimal, de la que derivan Perro y Vaca?". La respuesta es cuando tienes algo completamente fuera del árbol de herencia que también puede caminar, como un robot. Robot implementaría IWalkable, pero probablemente no derivaría de Animal. Si quieres una lista de cosas que pueden caminar,
Ahora reemplace IWalkable con algo más similar al software como IPersistable, y la analogía se acerca mucho más a lo que vería en un programa real.
fuente
Utilice interfaces cuando las implementaciones de la misma funcionalidad difieran.
Use un resumen / clases base cuando necesite compartir una implementación concreta común.
fuente
is
palabra clave)Piense en una interfaz como un contrato. Es una forma de decir: "Estas clases deberían seguir este conjunto de reglas".
Entonces, en el ejemplo de IAnimal, es una forma de decir: "DEBO poder llamar a Run, Walk, etc. en las clases que implementan IAnimal".
¿Por qué es útil esto? Es posible que desee crear una función que se base en el hecho de que debe poder llamar a Run and Walk, por ejemplo, en el objeto. Podría tener lo siguiente:
... y repite eso para todos los objetos que sabes que pueden correr y caminar. Sin embargo, con su interfaz IAnimal, puede definir la función una vez de la siguiente manera:
Al programar contra la interfaz, esencialmente confía en las clases para implementar la intención de la interfaz. Entonces, en nuestro ejemplo, el pensamiento es "No me importa cómo corren y caminen, siempre y cuando corran y caminen. Mi RunThenWalk será válido siempre que cumplan con ese acuerdo. Funciona perfectamente bien sin saber nada más sobre la clase."
También hay una buena discusión en esta pregunta relacionada .
fuente
No te preocupes tanto. Muchos desarrolladores rara vez necesitarán escribir una interfaz. Con frecuencia usará interfaces disponibles dentro del marco .NET , pero si no siente la necesidad de escribir una en el corto plazo, no hay nada sorprendente en eso.
El ejemplo que siempre le doy a alguien es si tienes una clase de velero y una clase de víbora. Heredan la clase Boat y la clase Car respectivamente. Ahora diga que necesita recorrer todos estos objetos y llamar a su
Drive()
método. Si bien podría escribir un código como el siguiente:Sería mucho más simple escribir:
fuente
Jimmy tiene razón cuando quiere poder usar una sola variable para varios tipos, pero todos esos tipos implementan el mismo método a través de una declaración de interfaz. Luego puede llamarlos método principal en la variable de interfaz de tipo.
Sin embargo, hay una segunda razón para usar interfaces. Cuando el arquitecto del proyecto es una persona diferente al codificador de implementación, o hay varios codificadores de implementación y un gerente de proyecto. La persona a cargo puede escribir un montón de interfaces y ver que el sistema interopera, y luego dejar que los desarrolladores completen las interfaces con las clases de implementación. Esta es la mejor manera de garantizar que varias personas escriban clases compatibles, y pueden hacerlo en paralelo.
fuente
Me gusta la analogía del ejército.
Al sargento no le importa si usted es un desarrollador de software , músico o abogado .
Te tratan como soldado .
Es más fácil para el sargento no molestarse con detalles específicos de las personas con las que está trabajando,
tratar a todos como abstracciones de soldados (... y castigarlos cuando no actúan como ellos).
La capacidad de las personas para actuar como soldados se llama polimorfismo.
Las interfaces son construcciones de software que ayudan a lograr el polimorfismo.
La necesidad de resumir los detalles para lograr la simplicidad es la respuesta a su pregunta.
fuente
En mi experiencia, la fuerza impulsora para crear interfaces no ocurrió hasta que comencé a hacer pruebas unitarias con un marco burlón. Quedó bastante claro que el uso de interfaces facilitaría mucho las burlas (ya que el marco dependía de que los métodos fueran virtuales). Una vez que comencé, vi el valor de abstraer la interfaz a mi clase de la implementación. Incluso si no creo una interfaz real, ahora trato de hacer que mis métodos sean virtuales (proporcionando una interfaz implícita que pueda ser anulada).
Hay muchas otras razones que he encontrado para reforzar la buena práctica de refactorizar las interfaces, pero la prueba de la unidad / burla fue lo que proporcionó el "momento aha" inicial de experiencia práctica.
EDITAR : Para aclarar, con las pruebas unitarias y las burlas siempre tengo dos implementaciones: la implementación real, concreta y una implementación alternativa simulada utilizada en las pruebas. Una vez que tenga dos implementaciones, el valor de la interfaz se vuelve obvio: trátelo en términos de la interfaz para que pueda reemplazar la implementación en cualquier momento. En este caso, lo estoy reemplazando con una interfaz simulada. Sé que puedo hacer esto sin una interfaz real si mi clase está construida correctamente, pero el uso de una interfaz real refuerza esto y lo hace más limpio (más claro para el lector). Sin este ímpetu, no creo que hubiera apreciado el valor de las interfaces ya que la mayoría de mis clases solo tienen una implementación concreta.
fuente
Algunos ejemplos que no son de programación que pueden ayudarlo a ver los usos apropiados de las interfaces en la programación.
Hay una interfaz entre los dispositivos eléctricos y la red eléctrica: es el conjunto de convenciones sobre la forma de los enchufes y enchufes y los voltajes / corrientes a través de ellos. Si desea implementar un nuevo dispositivo eléctrico, siempre que su enchufe siga las reglas, podrá obtener servicios de la red. Esto hace que la extensibilidad sea muy fácil y elimina o reduce los costos de coordinación : no tiene que notificar al proveedor de electricidad sobre cómo funciona su nuevo dispositivo y llegar a un acuerdo por separado sobre cómo conectar su nuevo dispositivo a la red.
Los países tienen medidores ferroviarios estándar. Esto permite una división del trabajo entre las compañías de ingeniería que bajan los rieles y las compañías de ingeniería que construyen trenes para correr en esos rieles, y hace posible que las compañías ferroviarias reemplacen y mejoren los trenes sin volver a armar todo el sistema.
El servicio que una empresa presenta a un cliente puede describirse como una interfaz: una interfaz bien definida enfatiza el servicio y oculta los medios . Cuando ingresa una carta en un buzón, espera que el sistema postal entregue la carta dentro de un tiempo determinado, pero no tiene expectativas sobre cómo se entrega la carta: no necesita saberlo , y el servicio postal tiene la flexibilidad para elija el medio de entrega que mejor cumpla con los requisitos y las circunstancias actuales. Una excepción a esto es la capacidad de los clientes de elegir el correo aéreo; ese no es el tipo de interfaz que un programador de computadoras moderno habría diseñado, ya que revela demasiada implementación.
Ejemplos de la naturaleza: no estoy demasiado interesado en los ejemplos de come (), makesSound (), move (), etc. Describen el comportamiento, que es correcto, pero no describen las interacciones y cómo están habilitadas . Los ejemplos obvios de interfaces que permiten interacciones en la naturaleza tienen que ver con la reproducción, por ejemplo, una flor proporciona una determinada interfaz a una abeja para que pueda tener lugar la polinización.
fuente
Es completamente posible pasar toda su vida como desarrollador de .net y nunca escribir sus propias interfaces. Después de todo, sobrevivimos bien sin ellos durante décadas y nuestros idiomas todavía estaban completos en Turing.
No puedo decirte por qué necesitas interfaces, pero puedo darte una lista de dónde las usamos en nuestro proyecto actual:
En nuestro modelo de complemento, cargamos los complementos por interfaz y proporcionamos esa interfaz a los escritores de complementos para que se ajusten.
En nuestro sistema de mensajería entre máquinas, todas las clases de mensajes implementan una interfaz específica y se "desenvuelven" utilizando la interfaz.
Nuestro sistema de gestión de configuración define una interfaz utilizada para establecer y recuperar ajustes de configuración.
Tenemos una interfaz que utilizamos para evitar un desagradable problema de referencia circular. (No hagas esto si no tienes que hacerlo).
Supongo que si hay una regla, es usar interfaces cuando desea agrupar varias clases dentro de una relación is-a, pero no desea proporcionar ninguna implementación en la clase base.
fuente
Un ejemplo de código (combinación de Andrew con un extra mío en cuál es el propósito de las interfaces ), que también explica por qué la interfaz en lugar de una clase abstracta en lenguajes sin soporte para herencia múltiple (c # y Java):
Observe que FileLogger y DataBaseLogger no necesitan la interfaz (podría ser una clase base abstracta de Logger). Pero tenga en cuenta que debe usar un registrador de terceros que lo obligue a usar una clase base (digamos que expone los métodos protegidos que necesita usar). Como el lenguaje no admite la herencia múltiple, no podrá utilizar el enfoque de clase base abstracta.
La conclusión es: use una interfaz cuando sea posible para obtener flexibilidad adicional en su código. Su implementación está menos vinculada, por lo que se adapta mejor al cambio.
fuente
He usado interfaces de vez en cuando y aquí está mi último uso (los nombres se han generalizado):
Tengo un montón de controles personalizados en un WinForm que necesitan guardar datos en mi objeto comercial. Un enfoque es llamar a cada control por separado:
El problema con esta implementación es que cada vez que agrego un control tengo que ingresar a mi método "Guardar datos" y agregar el nuevo control.
Cambié mis controles para implementar una interfaz ISaveable que tiene un método SaveToBusinessObject (...), así que ahora mi método "Guardar datos" solo recorre los controles y, si encuentra uno que sea ISaveable, llama a SaveToBusinessObject. Entonces, cuando se necesita un nuevo control, todo lo que alguien tiene que hacer es implementar ISaveable en ese objeto (y nunca tocar otra clase).
El beneficio a menudo no realizado para las interfaces es que localiza modificaciones. Una vez definido, rara vez cambiará el flujo general de una aplicación, pero a menudo hará cambios en el nivel de detalle. Cuando mantiene los detalles en objetos específicos, un cambio en ProcessA no afectará un cambio en ProcessB. (Las clases base también le brindan este beneficio).
EDITAR: Otro beneficio es la especificidad en las acciones. Como en mi ejemplo, todo lo que quiero hacer es guardar los datos; No me importa qué tipo de control es o si puede hacer algo más, solo quiero saber si puedo guardar los datos en el control. Hace que mi código de guardado sea bastante claro: no hay verificaciones para ver si es texto, numérico, booleano o lo que sea porque el control personalizado maneja todo eso.
fuente
Debe definir una interfaz una vez que necesite forzar un comportamiento para su clase.
El comportamiento de un animal puede implicar caminar, comer, correr, etc. Por lo tanto, usted los define como interfaces.
Otro ejemplo práctico es la interfaz ActionListener (o Runnable). Los implementaría cuando necesite realizar un seguimiento de un evento en particular. Por lo tanto, debe proporcionar la implementación del
actionPerformed(Event e)
método en su clase (o subclase). Del mismo modo, para la interfaz Runnable, proporciona la implementación delpublic void run()
método.Además, puede tener estas interfaces implementadas por cualquier número de clases.
Otra instancia en la que se utilizan interfaces (en Java) es implementar la herencia múltiple que se ofrece en C ++.
fuente
Suponga que desea modelar molestias que pueden ocurrir cuando intenta ir a dormir.
Modelo antes de interfaces
Como ve claramente, muchas 'cosas' pueden ser molestas cuando intenta dormir.
Uso de clases sin interfaces.
Pero cuando se trata de usar estas clases tenemos un problema. Ellos no tienen nada en comun. Tienes que llamar a cada método por separado.
Modelo con interfaces
Para superar esta sonda, podemos introducir una interfaz
E implementarlo dentro de clases
Uso con interfaces
Lo que facilitará mucho el uso de estas clases.
fuente
Neighbour
yLampJustOutsideYourWindow
también tiene que implementarAnnoying
?El ejemplo más fácil de dar es algo así como Procesadores de pago (Paypal, PDS, etc.).
Supongamos que crea una interfaz IPaymentProcessor que tiene los métodos ProcessACH y ProcessCreditCard.
Ahora puede implementar una implementación concreta de Paypal. Hacer que esos métodos llamen a funciones específicas de PayPal.
Si decide más adelante, necesita cambiar a otro proveedor, puede hacerlo. Simplemente cree otra implementación concreta para el nuevo proveedor. Como todo lo que está vinculado es su interfaz (contrato), puede cambiar cuál usa su aplicación sin cambiar el código que la consume.
fuente
También le permite realizar pruebas de unidades simuladas (.Net). Si su clase usa una interfaz, puede burlarse del objeto en la prueba de su unidad y probar fácilmente la lógica (sin llegar a la base de datos, al servicio web, etc.).
http://www.nmock.org/
fuente
Si explora los ensamblados de .NET Framework y profundiza en las clases base para cualquiera de los objetos estándar, notará muchas interfaces (miembros nombrados como ISomeName).
Las interfaces son básicamente para implementar marcos, grandes o pequeños. Sentí lo mismo acerca de las interfaces hasta que quise escribir un marco propio. También descubrí que la comprensión de las interfaces me ayudó a aprender marcos mucho más rápidamente. En el momento en que desee escribir una solución más elegante para casi cualquier cosa, encontrará que una interfaz tiene mucho sentido. Es como un método para dejar que una clase se ponga la ropa adecuada para el trabajo. Más importante aún, las interfaces permiten que los sistemas se documenten mucho más, porque los objetos complejos se vuelven menos complejos cuando la clase implementa interfaces, lo que ayuda a clasificar su funcionalidad.
Las clases implementan interfaces cuando quieren poder participar en un marco explícita o implícitamente. Por ejemplo, IDisposable es una interfaz común que proporciona la firma del método para el método popular y útil Dispose (). En un marco, todo lo que usted u otro desarrollador necesita saber sobre una clase es que si implementa IDisposable, entonces sabe que ((IDisposable) myObject) .Dispose () está disponible para ser llamado con fines de limpieza.
EJEMPLO CLÁSICO: sin implementar la interfaz IDisposable, no puede usar la construcción de palabras clave "using ()" en C #, porque requiere que cualquier objeto especificado como parámetro se pueda convertir implícitamente en IDisposable.
EJEMPLO COMPLEJO: Un ejemplo más complejo sería la clase System.ComponentModel.Component. Esta clase implementa tanto IDisposable como IComponent. La mayoría, si no todos, los objetos .NET que tienen un diseñador visual asociado con ellos implementan IComponent para que el IDE pueda interactuar con el componente.
CONCLUSIÓN: A medida que se familiarice con .NET Framework, lo primero que hará cuando encuentre una nueva clase en el Explorador de objetos o dentro de la herramienta .NET Reflector (gratuita) ( http://www.red-gate.com / products / reflector / ) es verificar para ver de qué clase hereda y también las interfaces que implementa. .NET Reflector es incluso mejor que el Navegador de objetos porque también le permite ver las clases Derivadas. Eso le permite aprender acerca de todos los objetos que se derivan de una clase en particular, por lo tanto, potencialmente aprender sobre la funcionalidad del marco que no sabía que existía. Esto es particularmente significativo cuando se agregan espacios de nombres nuevos o actualizados a .NET Framework.
fuente
Considera que estás haciendo un juego de disparos en primera persona. El jugador tiene múltiples armas para elegir.
Podemos tener una interfaz
Gun
que defina una funciónshoot()
.Necesitamos diferentes subclases de
Gun
clase, a saber,ShotGun
Sniper
etc.Clase tirador
El tirador tiene todas las armas en su armadura. Vamos a crear un
List
para representarlo.El tirador recorre sus pistolas, según sea necesario, utilizando la función
switchGun()
Podemos configurar la pistola actual, usando la función anterior y simplemente llamar a la
shoot()
función, cuandofire()
se llama.El comportamiento de la función de disparo variará según las diferentes implementaciones de
Gun
interfaz.Conclusión
Cree una interfaz, cuando una función de clase depende de una función de otra clase , que está sujeta a cambios en su comportamiento, en función de la instancia (objeto) de la clase implementada.
por ejemplo, la
fire()
función de laShooter
clase espera que guns (Sniper
,ShotGun
) implemente lashoot()
función. Entonces si cambiamos el arma y disparamos.Hemos cambiado el comportamiento de la
fire()
función.fuente
Para ampliar lo que Larsenal ha dicho. Una interfaz es un contrato que todas las clases implementadoras deben seguir. Debido a esto, puede usar una técnica llamada programación para el contrato. Esto permite que su software se vuelva independiente de la implementación.
fuente
Las interfaces se usan generalmente cuando se desea definir un comportamiento que los objetos pueden exhibir.
Un buen ejemplo de esto en el mundo .NET es la interfaz IDisposable , que se usa en cualquier clase de Microsoft que use recursos del sistema que deben liberarse manualmente. Requiere que la clase que lo implementa tenga un método Dispose ().
(El método Dispose () también se llama mediante el uso de la construcción del lenguaje para VB.NET y C # , que solo funciona en
IDisposable
s)Tenga en cuenta que puede verificar si un objeto implementa una interfaz específica mediante el uso de construcciones como
TypeOf ... Is
(VB.NET),is
(C #),instanceof
(Java), etc.fuente
Como probablemente varias personas ya hayan respondido, las interfaces se pueden usar para imponer ciertos comportamientos entre clases que no implementarán esos comportamientos de la misma manera. Entonces, al implementar una interfaz, usted dice que su clase tiene el comportamiento de la interfaz. La interfaz IAnimal no sería una interfaz típica porque las clases de perros, gatos, pájaros, etc. son tipos de animales, y probablemente deberían extenderla, lo cual es un caso de herencia. En cambio, una interfaz se parecería más al comportamiento animal en este caso, como IRunnable, IFlyable, ITrainable, etc.
Las interfaces son buenas para muchas cosas, una de las cosas clave es la capacidad de conexión. Por ejemplo, declarar un método que tenga un parámetro de Lista permitirá que se pase cualquier cosa que implemente la interfaz de Lista, permitiendo al desarrollador eliminar y conectar una lista diferente más adelante sin tener que volver a escribir una tonelada de código.
Es posible que nunca use interfaces, pero si está diseñando un proyecto desde cero, especialmente un marco de trabajo de algún tipo, probablemente querrá familiarizarse con ellas.
Recomendaría leer el capítulo sobre interfaces en Java Design de Coad, Mayfield y Kern. Lo explican un poco mejor que el texto introductorio promedio. Si no usa Java, puede leer el comienzo del capítulo, que es principalmente conceptos.
fuente
Como cualquier técnica de programación que agregue flexibilidad a su sistema, las interfaces también agregan cierto nivel de complejidad. A menudo son geniales y puede usarlo en todas partes (puede crear una interfaz para todas sus clases), pero al hacerlo, crearía un sistema más complejo que sería más difícil de mantener.
Aquí hay una compensación, como de costumbre: flexibilidad sobre mantenibilidad. Cual es mas importante ? No hay respuestas, depende del proyecto. Pero recuerde que todos los softwares deberán mantenerse ...
Así que mi consejo: no uses interfaces hasta que realmente las necesites. (Con Visual Studio, puede extraer una interfaz de una clase existente en 2 segundos, así que no se apure).
Habiendo dicho eso, ¿cuándo necesitas crear una interfaz?
Lo hago cuando estoy refactorizando un método que de repente necesita procesar dos o más clases similares. Luego creo una interfaz, asigno esta interfaz a las dos (o más) clases similares y cambio el tipo de parámetro del método (reemplace el tipo de clase con el tipo de interfaz).
Y funciona: o)
Una excepción: cuando me burlo de los objetos, la interfaz es mucho más fácil de usar. Así que a menudo creo una interfaz solo para esto.
PD: cuando escribo "interfaz", quiero decir: "interfaz de cualquier clase base", incluidas las clases de interfaz pura. Tenga en cuenta que las clases abstractas suelen ser una mejor apuesta que las interfaces puras, ya que puede agregarles lógica.
Saludos, Sylvain.
fuente
Las interfaces se harán evidentes cuando se convierta en un desarrollador de bibliotecas (alguien que codifique para otros codificadores). La mayoría de nosotros comenzamos como desarrolladores de aplicaciones , donde usamos las API existentes y las bibliotecas de programación.
En la misma línea que las interfaces son un contrato , nadie mencionó aún que las interfaces son una excelente manera de estabilizar algunas partes de su código . Eso es especialmente útil cuando se trata de un proyecto de equipo (o cuando está desarrollando código utilizado por otros desarrolladores). Entonces, aquí hay un escenario concreto para usted:
Consulte también esta pregunta relacionada sobre la codificación de una interfaz .
fuente
Hay tantos propósitos para usar una interfaz.
Uso en comportamiento polimórfico. Donde desee llamar a métodos específicos de una clase secundaria con una interfaz que tenga una referencia a la clase secundaria.
Tener un contrato con las clases para implementar todos los métodos donde sea necesario, como el uso más común es con objetos COM, donde se genera una clase contenedora en un archivo DLL que hereda la interfaz; Estos métodos se llaman detrás de escena, y solo necesita implementarlos pero con la misma estructura definida en la DLL de COM que solo puede conocer a través de la interfaz que exponen.
Para reducir el uso de memoria cargando métodos específicos en una clase. Al igual que si tiene tres objetos comerciales y se implementan en una sola clase, puede usar tres interfaces.
Por ejemplo, IUser, IOrder, IOrderItem
Si solo desea agregar un usuario, haga lo siguiente:
fuente