design patterns - patterns - ¿Cómo sabré cuándo crear una interfaz?
patrones de diseño java (24)
Algunos ejemplos que no son de programación y que pueden ayudarlo a ver los usos apropiados de las interfaces en la programación.
Existe 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 que los atraviesan. 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 el funcionamiento de 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 de ferrocarril estándar. Esto permite una división del trabajo entre las empresas de ingeniería que destruyen los raíles y las empresas de ingeniería que construyen trenes para que funcionen en esos raíles, y hace posible que las compañías ferroviarias reemplacen y mejoren trenes sin tener que reorganizar todo el sistema.
El servicio que un negocio presenta a un cliente se puede describir como una interfaz: una interfaz bien definida enfatiza el servicio y oculta los medios . Cuando coloca una carta en un buzón de correo, 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 de elija los medios de entrega que mejor se ajusten a los requisitos y circunstancias actuales. Una excepción a esto es la capacidad de los clientes de elegir correo aéreo: esa no es la clase de interfaz que un programador de computadoras moderno habría diseñado, ya que revela demasiado de la implementación.
Ejemplos de la naturaleza: no estoy muy interesado en los ejemplos de come (), makesSound (), moves (), etc. Sí 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 cierta interfaz a una abeja para que pueda tener lugar la polinización.
Estoy en un punto en mi aprendizaje de desarrollo donde siento que debo aprender más sobre interfaces.
Con frecuencia leo sobre ellos, pero parece que no puedo entenderlos.
He leído ejemplos como: Clase base animal, con IAnimal interfaz para cosas como ''Walk'', ''Run'', ''GetLegs'', etc. - pero nunca he estado trabajando en algo y me siento como "Hey, debería usar una interfaz ¡aquí!"
¿Qué me estoy perdiendo? ¿Por qué es un concepto tan difícil de entender para mí? Simplemente 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 faltante de entenderlos! ¡Me hace sentir que me estoy perdiendo algo arriba en términos de ser un 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.
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 puedes usarlo en todas partes (puedes crear una interfaz para todas tus clases), pero al hacerlo, crearías un sistema más complejo que sería más difícil de mantener.
Aquí hay una compensación, como de costumbre: flexibilidad sobre la mantenibilidad. Cual es mas importante ? No hay respuestas, depende del proyecto. Pero recuerda 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 refacturando 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 tengo que simular 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 puras. Tenga en cuenta que las clases abstractas suelen ser una mejor apuesta que las interfaces puras, ya que puede agregarles lógica.
Saludos, Sylvain.
Como es probable que 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, estás diciendo que tu clase tiene el comportamiento de la interfaz. La interfaz IAnimal no sería una interfaz típica porque las clases de Perro, Gato, Pájaro, etc. son tipos de animales, y probablemente deberían extenderlo, que es un caso de herencia. En cambio, una interfaz sería más parecida al comportamiento animal en este caso, como IRunnable, IFlyable, ITrainable, etc.
Las interfaces son buenas para muchas cosas, una de las claves es la capacidad de conexión. Por ejemplo, declarar un método que tenga un parámetro de Lista permitirá que todo lo que implemente la interfaz de la Lista sea pasado, permitiendo al desarrollador eliminar y conectar una lista diferente en un momento posterior sin tener que reescribir una tonelada de código.
Es posible que nunca uses interfaces, pero si estás diseñando un proyecto desde cero, especialmente un marco de algún tipo, es probable que quieras familiarizarte con ellos.
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 principio del capítulo, que es principalmente conceptos.
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 define una función shoot()
.
Necesitamos diferentes subclases de clase Gun
, a saber, ShotGun
Sniper
etc.
ShotGun implements Gun{
public void shoot(){
//shotgun implementation of shoot.
}
}
Sniper implements Gun{
public void shoot(){
//sniper implementation of shoot.
}
}
Shooter Class
El tirador tiene todas las armas en su Armadura. Vamos a crear una List
para representarlo.
List<Gun> listOfGuns = new ArrayList<Gun>();
El tirador recorre sus pistolas, cuando sea necesario, usando la función de cambio de switchGun()
public void switchGun(){
//code to cycle through the guns from the list of guns.
currentGun = //the next gun in the list.
}
Podemos configurar la pistola actual, usando la función anterior y simplemente llamar a la función shoot()
, cuando se fire()
.
public void fire(){
currentGun.shoot();
}
El comportamiento de la función de disparar variará según las diferentes implementaciones de la interfaz de Gun
.
Conclusión
Cree una interfaz, cuando una función de clase depende de una función de otra clase , que está sujeta a cambiar su comportamiento, en función de la instancia (objeto) de la clase implementada.
por ejemplo, la función fire()
de la clase Shooter
espera que las pistolas ( Sniper
, ShotGun
) implementen la función shoot()
. Entonces si cambiamos el arma y disparamos.
shooter.switchGun();
shooter.fire();
Hemos cambiado el comportamiento de la función fire()
.
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, los define como interfaces.
Otro ejemplo práctico es la interfaz ActionListener (o Runnable). Los implementarías cuando necesites hacer un seguimiento de un evento en particular. Por lo tanto, debe proporcionar la implementación del actionPerformed(Event e)
en su clase (o subclase). De forma similar, para la interfaz Runnable, usted proporciona la implementación para el método public void run()
.
Además, puede tener estas interfaces implementadas por cualquier cantidad de clases.
Otra instancia donde se usan interfaces (en Java) es implementar la herencia múltiple ofrecida en C ++.
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 luego decide que necesita cambiarse 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 utiliza su aplicación sin cambiar el código que la consume.
En mi experiencia, la fuerza impulsora para crear interfaces no se produjo hasta que comencé a hacer pruebas unitarias con un marco de burla. Resultó muy claro que el uso de interfaces iba a hacer que la burla fuera mucho más fácil (ya que el marco dependía de que los métodos fueran virtuales). Una vez que comencé, vi el valor de abstraer la interfaz de mi clase de la implementación. Incluso si no creo una interfaz real, intento ahora hacer que mis métodos sean virtuales (proporcionando una interfaz implícita que se puede anular).
Hay muchas otras razones que he encontrado para reforzar la buena práctica de refactorizar a las interfaces, pero la prueba unitaria / burla fue lo que brindó el "momento clave" de la experiencia práctica.
EDITAR : Para aclarar, con las pruebas unitarias y las burlas, siempre tengo dos implementaciones: la implementación real y concreta y una implementación simulada alternativa utilizada en las pruebas. Una vez que tiene dos implementaciones, el valor de la interfaz se vuelve obvio: trate con eso 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 única implementación concreta.
Es completamente posible utilizar toda tu vida como desarrollador de .net y nunca escribir tus propias interfaces. Después de todo, sobrevivimos bien sin ellos durante décadas y nuestros idiomas todavía estaban completos.
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 complementos por interfaz y proporcionamos esa interfaz a los escritores de plugins para cumplir.
En nuestro sistema de mensajería intermachine, 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 configuraciones.
Tenemos una interfaz que utilizamos para evitar un desagradable problema de referencia circular. (No haga esto si no tiene que hacerlo).
Supongo que si hay una regla, es utilizar interfaces cuando se quiere agrupar varias clases dentro de una relación is-a, pero no se desea proporcionar ninguna implementación en la clase base.
Hay tantos propósitos para usar una interfaz.
Usar en comportamiento polimórfico. Donde desea llamar a métodos específicos de una clase infantil con una interfaz que tiene 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 una DLL que hereda la interfaz; estos métodos se llaman detrás de escena, y solo necesita implementarlos pero con la misma estructura que se define en la DLL 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
public interface IUser()
{
void AddUser(string name ,string fname);
}
// Same for IOrder and IOrderItem
//
public class BusinessLayer: IUser, IOrder, IOrderItem
{
public void AddUser(string name ,string fname)
{
// Do stuffs here.
}
// All methods from all interfaces must be implemented.
}
Si solo desea agregar un usuario, haga esto:
IUser user = new (IUser)BusinessLayer();
// It will load all methods into memory which are declared in the IUser interface.
user.AddUser();
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:
myBusinessObject.Save(controlA.Data);
myBusinessObject.Save(controlB.Data);
myBusinessObject.Save(controlC.Data);
El problema con esta implementación es que cada vez que agrego un control, tengo que entrar en mi método "Guardar datos" y agregar el nuevo control.
Cambié mis controles para implementar una interfaz ISaveable que tiene un método SaveToBusinessObject (...) por lo que ahora mi método "Guardar datos" simplemente itera a través de 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).
foreach(Control c in Controls)
{
ISaveable s = c as ISaveable;
if( s != null )
s.SaveToBusinessObject(myBusinessObject);
}
El beneficio a menudo no realizado de las interfaces es que localizas 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 dan 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 sea o si puede hacer otra cosa. Solo quiero saber si puedo guardar los datos en el control. Hace que mi código de guardado sea bastante claro: no hay controles para ver si es texto, numérico, booleano o lo que sea, porque el control personalizado maneja todo eso.
Jimmy tiene razón, cuando quiere poder usar una sola variable para múltiples 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 tipo de interfaz.
Sin embargo, hay una segunda razón para usar interfaces. Cuando el arquitecto del proyecto es una persona diferente del 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 rellenen 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.
Las interfaces generalmente se usan cuando se quiere 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 se deben liberar manualmente. Requiere que la clase que lo implementa tenga un método Dispose ().
(El método de uso de lenguaje también utiliza el método Dispose () 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 utilizando construcciones como TypeOf ... Is
(VB.NET), is
(C #), instanceof
(Java), etc.
Las interfaces se harán evidentes cuando te conviertas en un desarrollador de la biblioteca (alguien que codifica para otros codificadores). La mayoría de nosotros comienza como desarrolladores de aplicaciones , donde utilizamos API existentes y 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 hacer que algunas partes de su código sean estables . Eso es especialmente útil cuando se trata de un proyecto de equipo (o cuando está desarrollando código usado por otros desarrolladores). Entonces, aquí hay un escenario concreto para ti:
Cuando está desarrollando código en un equipo , es posible que otros estén usando el código que usted escribe. Serán muy felices cuando codifiquen en sus interfaces (estables), y usted estará contento cuando tenga la libertad de cambiar sus implementaciones (ocultas detrás de la interfaz) sin romper el código de su equipo. Es una variante del ocultamiento de la información (las interfaces son públicas, las implementaciones están ocultas para los programadores del cliente). Lea más acerca de las variaciones protegidas .
Consulte también esta pregunta relacionada sobre la codificación de una interfaz .
Me gusta la analogía del ejército.
Al sargento no le importa si usted es un desarrollador de software , músico o abogado .
Usted es tratado como soldado .
Es más fácil para el sargento no molestarse con los detalles específicos de las personas con las que está trabajando,
tratar a todos como abstracciones de soldados (... y castigarlos cuando no actúen 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 abstraer detalles para lograr simplicidad es la respuesta a su pregunta.
Polymorphism , que etimológicamente significa "muchas formas", es la capacidad de tratar un objeto de cualquier subclase de una clase base como si fuera un objeto de la clase base. Una clase base tiene, por lo tanto, muchas formas: la clase base misma y cualquiera de sus subclases.
(...) Esto hace que su código sea más fácil de escribir y más fácil de entender para otros. También hace que su código sea extensible, porque otras subclases podrían agregarse más adelante a la familia de tipos, y los objetos de esas nuevas subclases también funcionarían con el código existente.
Me gusta mucho la respuesta de Jimmy, pero siento que necesito agregarle algo. La clave de todo es que el "capaz" en IP puede hacerlo. 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 tu sistema tiene muchas cosas que pueden hacer. Es posible que tenga clases derivadas de animales como perro, vaca, pescado, serpiente. Los dos primeros probablemente implementarían IWalkable, los dos últimos no caminarían, por lo que no lo harían. Ahora pregunta: "¿por qué no tener otra superclase, WalkingAnimal, de la que derivan Dog and Cow?". 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, la escribes como IWalkable y puedes incluir todos los animales que caminan más robots en la lista.
Ahora reemplace IWalkable con algo más de software, como IPersistable, y la analogía se acerca mucho más a lo que vería en un programa real.
No te preocupes tanto Muchos desarrolladores rara vez necesitarán escribir una interfaz. Con frecuencia utilizará las interfaces disponibles dentro del framework .NET , pero si no siente la necesidad de escribir una en cualquier momento, no hay nada de sorprendente en eso.
El ejemplo que siempre le doy a alguien es si tiene una clase de velero y una clase Viper. Ellos heredan la clase de Barco y la clase de Coche respectivamente. Ahora diga que necesita recorrer todos estos objetos y llamar a su método Drive()
. Si bien podrías escribir algunos códigos como los siguientes:
if(myObject is Boat)
((Boat)myObject).Drive()
else
if (myObject is Car)
((Car)myObject).Drive()
Sería mucho más simple escribir:
((IDrivable)myObject).Drive()
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 del contrato. Esto permite que su software se convierta en una implementación independiente.
Piense en una interfaz como un contrato. Es una forma de decir: "Estas clases deben seguir estas reglas".
Entonces, en el ejemplo de IAnimal, es una forma de decir: "DEBO poder llamar Run, Walk, etc. en las clases que implementan IAnimal".
¿Por qué es esto útil? Es posible que desee crear una función que dependa del hecho de que debe poder ejecutar Ejecutar y recorrer, por ejemplo, en el objeto. Usted podría tener lo siguiente:
public void RunThenWalk(Monkey m) {
m.Run();
m.Walk();
}
public void RunThenWalk(Dog d) {
d.Run();
d.Walk();
}
... 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:
public void RunThenWalk(IAnimal a) {
a.Run();
a.Walk();
}
Al programar contra la interfaz, básicamente está confiando en que las clases implementen la intención de la interfaz. Entonces, en nuestro ejemplo, la idea es "No me importa cómo corran y caminen, siempre y cuando corran y caminen. Mi RunThenWalk será válido siempre y cuando 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 .
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 sobre las interfaces hasta que quise escribir un marco propio. También encontré que las interfaces de comprensión me ayudaron 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 sean mucho más autodocumentados, porque los objetos complejos se vuelven menos complejos cuando la clase implementa interfaces, lo que ayuda a categorizar su funcionalidad.
Las clases implementan interfaces cuando quieren poder participar en un marco de forma explícita o implícita. Por ejemplo, IDisposable es una interfaz común que proporciona la firma de métodos para el popular y útil método Dispose (). En un marco, todo lo que usted u otro desarrollador necesita saber sobre una clase es que si implementa IDisposable, entonces sabrá que ((IDisposable) myObject) .Dispose () está disponible para ser invocado con fines de limpieza.
EJEMPLO CLÁSICO: sin implementar la interfaz IDisposable, no puede usar la construcción de palabra 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 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 Examinador de objetos o dentro de la herramienta Reflector de .NET (gratuita) ( http://www.red-gate.com/products/reflector/ ) es comprobar para ver de qué clase hereda y también las interfaces que implementa. .NET Reflector es incluso mejor que el Object Browser porque también te permite ver las clases derivadas. Eso le permite aprender acerca de todos los objetos que se derivan de una clase en particular, con lo que potencialmente puede aprender acerca de la funcionalidad del marco que usted no sabía que existía. Esto es particularmente significativo cuando se agregan espacios de nombres nuevos o actualizados a .NET Framework.
Suponga que desea querer modelar las molestias que pueden ocurrir cuando intenta dormirse.
Modelo antes de las interfaces
class Mosquito {
void flyAroundYourHead(){}
}
class Neighbour{
void startScreaming(){}
}
class LampJustOutsideYourWindow(){
void shineJustThroughYourWindow() {}
}
Como puede ver 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.
class TestAnnoyingThings{
void testAnnoyingThinks(Mosquito mosquito, Neighbour neighbour, LampJustOutsideYourWindow lamp){
if(mosquito != null){
mosquito.flyAroundYourHead();
}
if(neighbour!= null){
neighbour.startScreaming();
}
if(lamp!= null){
lamp.shineJustThroughYourWindow();
}
}
}
Modelo con interfaces
Para superar este problema, podemos presentar una interfaz
interface Annoying{
public void annoy();
}
E implementarlo dentro de las clases
class Mosquito implements Annoying {
void flyAroundYourHead(){}
void annoy(){
flyAroundYourHead();
}
}
class Neighbour implements Annoying{
void startScreaming(){}
void annoy(){
startScreaming();
}
}
class LampJustOutsideYourWindow implements Annoying{
void shineJustThroughYourWindow() {}
void annoy(){
shineJustThroughYourWindow();
}
}
Uso con interfaces
Lo cual hará que el uso de estas clases sea mucho más fácil
class TestAnnoyingThings{
void testAnnoyingThinks(Annoying annoying){
annoying.annoy();
}
}
También le permite realizar pruebas de unidades simuladas (.Net). Si su clase utiliza una interfaz, puede simular el objeto en las pruebas de su unidad y probar fácilmente la lógica (sin llegar a la base de datos, el servicio web, etc.).
Un ejemplo de código (combinación de Andrew con un extra mío en what-is-the-purpose-of-interfaces ), que también explica por qué la interfaz en lugar de una clase abstracta en idiomas sin soporte para herencia múltiple (c # y Java):
interface ILogger
{
void Log();
}
class FileLogger : ILogger
{
public void Log() { }
}
class DataBaseLogger : ILogger
{
public void Log() { }
}
public class MySpecialLogger : SpecialLoggerBase, ILogger
{
public void Log() { }
}
Tenga en cuenta que FileLogger y DataBaseLogger no necesitan la interfaz (podría ser una clase base abstracta de Logger). Pero considere que debe usar un registrador de terceros que lo obligue a utilizar una clase base (supongamos que expone los métodos protegidos que necesita usar). Como el idioma no es compatible con herencia múltiple, no podrá utilizar el enfoque de clase base abstracta.
En pocas palabras: use una interfaz cuando sea posible para obtener flexibilidad adicional en su código. Su implementación está menos vinculada, por lo que se acomoda mejor para el cambio.
Use interfaces cuando las implementaciones de la misma funcionalidad serán diferentes.
Use una clase abstracta / base cuando necesite compartir una implementación concreta común.
resuelve este problema concreto:
tienes a, b, c, d de 4 tipos diferentes. todo su código tiene algo como:
a.Process();
b.Process();
c.Process();
d.Process();
¿por qué no hacer que implementen IProcessable, y luego hacer
List<IProcessable> list;
foreach(IProcessable p in list)
p.Process();
esto escalará mucho mejor cuando agrega, 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 dice "Admito la iteración en un patrón de tipo foreach no ordenado", puede definir comportamientos complejos (Count, Max, Where, Select, etc.) para cualquier tipo enumerable.