¿Cómo sabré cuándo crear una interfaz?

196

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.

usuario53885
fuente
1
Debe consultar stackoverflow.com/q/8531292/1055241
gprathour

Respuestas:

151

resuelve este problema concreto:

tienes a, b, c, d de 4 tipos diferentes. en todo tu código tienes algo como:

a.Process();
b.Process();
c.Process();
d.Process();

por qué no hacer que implementen IProcessable y luego

List<IProcessable> list;

foreach(IProcessable p in list)
    p.Process();

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.

Palanqueta
fuente
2
Eso ayuda. ¿Cuál es la ventaja de tener una interfaz presente en lugar de tener los tipos simplemente implementados para el método Process ()?
user53885
No podría usar la misma variable p a menos que todas fueran subclases del mismo tipo base o implementaran la interfaz.
Karl
No tiene que emitir, a diferencia de 50 clases diferentes con un método de proceso. C # no usa "tipear pato", por lo que el hecho de que A tenga Process () y B tenga Process () no significa que haya una forma genérica de llamar tampoco. Necesita una interfaz para eso.
user7116
Derecha. Acabo de cambiar "var" a "IProcessable" para que el ejemplo tenga más sentido.
Jimmy el
2
@Rogerio: Estaba tratando de ser genérico. El punto no es que "cuando tienes cosas que tienen una función Process ()" es "cuando tienes cosas que comparten un conjunto común de métodos". el ejemplo se puede cambiar fácilmente aforeach(IMyCompanyWidgetFrobber a in list) a.Frob(widget, context);
Jimmy
133

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.

rmeador
fuente
9
Me gusta lo que se te ocurrió: "Indica una capacidad". Las interfaces son realmente necesarias cuando tiene que definir la capacidad porque lo básico tiene que apegarse a su clase "Base".
Ramiz Uddin
72

Utilice interfaces cuando las implementaciones de la misma funcionalidad difieran.

Use un resumen / clases base cuando necesite compartir una implementación concreta común.

Elemento
fuente
8
El primero se llama polimorfismo. El segundo es el aceite de serpientes, a menos que sublcass sea ​​de clase base (no hay violación del principio de sustitución de Liskov), debe favorecer la composición sobre la herencia.
Arnis Lapsa
@ArnisLapsa No entiendo lo que quieres decir con "a menos que sublcass sea clase base". ¿Cuándo una subclase no "sería" clase base? (como en la ispalabra clave)
Marc.2377
32

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:

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, 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 .

Larsenal
fuente
1
No se olvide de la independencia de implementación. Una interfaz le permite a uno no importarle cómo se implementa la función subyacente, solo que hace lo que la interfaz dice que hace.
Matthew Brubaker el
18

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:

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()
Spencer Ruport
fuente
16

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.

Karl
fuente
15

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 .

uml

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.

El polimorfismo , 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 en sí misma y cualquiera de sus subclases.

(..) Esto hace que su código sea más fácil de escribir y que otros lo entiendan. También hace que su código sea extensible, porque otras subclases podrían agregarse más tarde a la familia de tipos, y los objetos de esas nuevas subclases también funcionarían con el código existente.

Arnis Lapsa
fuente
14

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.

tvanfosson
fuente
Lo correcto por razones equivocadas. En su caso: terminará con las llamadas "interfaces de encabezado" y la complejidad añadida sobreponderaciones lograron simplicidad.
Arnis Lapsa
@Arnis: las pruebas unitarias son una "razón incorrecta", burlarse fácilmente de las clases para eliminar dependencias en las pruebas es una "razón incorrecta". Lo siento, pero no estoy de acuerdo.
tvanfosson
1
Las pruebas deben influir indirectamente en el diseño al proporcionar retroalimentación si el código es o no comprobable. Agregar puntos de extensibilidad para mejorar la capacidad de prueba en sí misma es como hacer trampa. Creo que Mark Seeman lo resume mejor bit.ly/esi8Wp
Arnis Lapsa
1
@Arnis: ¿utilizas simulacros en tus pruebas unitarias? Si no es así, ¿cómo se elimina la dependencia de las dependencias? ¿Estás usando DI en absoluto? Las pruebas unitarias me llevaron a usar burlas y DI; burlarse y DI demostraron el valor de la buena práctica de usar interfaces para definir contratos de una manera que ninguna comprensión académica nunca podría. Debido a mi adopción de TDD, mi código está mucho menos acoplado de lo que hubiera estado de otra manera. Creo que eso es bueno.
tvanfosson
Simplemente diciendo que la descomposición que no se encuentra en las llamadas juntas naturales conduce a una baja cohesión y una complejidad innecesaria.
Arnis Lapsa
10

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
5

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:

  1. En nuestro modelo de complemento, cargamos los complementos por interfaz y proporcionamos esa interfaz a los escritores de complementos para que se ajusten.

  2. 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.

  3. Nuestro sistema de gestión de configuración define una interfaz utilizada para establecer y recuperar ajustes de configuración.

  4. 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.

Sí, ese Jake.
fuente
5

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):

interface ILogger
{
    void Log();
}
class FileLogger : ILogger
{
    public void Log() { }
}
class DataBaseLogger : ILogger
{
    public void Log() { }
}
public class MySpecialLogger : SpecialLoggerBase, ILogger
{
    public void Log() { }
}

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.

eglasius
fuente
4

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 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).

foreach(Control c in Controls)
{
  ISaveable s = c as ISaveable;

  if( s != null )
      s.SaveToBusinessObject(myBusinessObject);
}

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.

Austin Salonen
fuente
4

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 del public 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 ++.

Epitafio
fuente
3
Por favor, Dios haga que dejen de decir cosas como herencia múltiple con respecto a las interfaces. Usted NO hereda una interfaz en una clase. Lo implementas .
Andrei Rînea
4

Suponga que desea modelar molestias que pueden ocurrir cuando intenta ir a dormir.

Modelo antes de interfaces

ingrese la descripción de la imagen aquí

class Mosquito {
    void flyAroundYourHead(){}
}

class Neighbour{
    void startScreaming(){}
}

class LampJustOutsideYourWindow(){
    void shineJustThroughYourWindow() {}
}

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.

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 esta sonda, podemos introducir una interfazingrese la descripción de la imagen aquí

interface Annoying{
   public void annoy();

}

E implementarlo dentro de 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 que facilitará mucho el uso de estas clases.

class TestAnnoyingThings{
    void testAnnoyingThinks(Annoying annoying){
        annoying.annoy();
    }
}
Marcin Szymczak
fuente
Ok, pero no tiene Neighboury LampJustOutsideYourWindowtambién tiene que implementar Annoying?
Stardust
Sí, gracias por señalar eso. He realizado una edición con este cambio
Marcin Szymczak
2

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.

Pinchazo
fuente
2

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/

Jobo
fuente
2

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.

EnocNRoll - AnandaGopal Pardue
fuente
2

Considera que estás haciendo un juego de disparos en primera persona. El jugador tiene múltiples armas para elegir.

Podemos tener una interfaz Gunque defina una función shoot().

Necesitamos diferentes subclases de Gunclase, a saber, ShotGun Sniperetc.

ShotGun implements Gun{
    public void shoot(){
       \\shotgun implementation of shoot.
    } 
}

Sniper implements Gun{
    public void shoot(){
       \\sniper implementation of shoot.
    } 
}

Clase tirador

El tirador tiene todas las armas en su armadura. Vamos a crear un Listpara representarlo.

List<Gun> listOfGuns = new ArrayList<Gun>();

El tirador recorre sus pistolas, según sea necesario, utilizando la función 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 shoot()función, cuando fire()se llama.

public void fire(){
    currentGun.shoot();
}

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 la Shooterclase espera que guns ( Sniper, ShotGun) implemente la shoot()función. Entonces si cambiamos el arma y disparamos.

shooter.switchGun();
shooter.fire();

Hemos cambiado el comportamiento de la fire()función.

Clasificador
fuente
1

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.

Matthew Brubaker
fuente
1

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 IDisposables)

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.

Powerlord
fuente
1

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.

Ryan Thames
fuente
1

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.

Sylvain Rodrigue
fuente
1

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:

Cuando desarrolle código en un equipo , posiblemente otros usarán el código que usted escribe. Serán más felices cuando codifiquen en sus interfaces (estables), y usted será feliz 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 de ocultación de información (las interfaces son públicas, las implementaciones están ocultas para los programadores del cliente). Lea más sobre variaciones protegidas .

Consulte también esta pregunta relacionada sobre la codificación de una interfaz .

Fuhrmanator
fuente
1

Hay tantos propósitos para usar una interfaz.

  1. 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.

  2. 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.

  3. 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 lo siguiente:

IUser user = new (IUser)BusinessLayer();

// It will load  all methods into memory which are declared in the IUser interface.

user.AddUser();
Marc.2377
fuente