¿Cuál es la diferencia entre una interfaz y una clase, y por qué debería usar una interfaz cuando puedo implementar los métodos directamente en la clase?


117

Soy consciente de que esta es una pregunta muy básica, pero un entrevistador me preguntó de una manera muy engañosa y yo estaba indefenso :(

Solo conozco la definición material o teórica de una interfaz y también la implementé en muchos proyectos en los que trabajé. Pero realmente no entiendo por qué y cómo es útil.

Tampoco entiendo una cosa en la interfaz. es decir, por ejemplo, usamos

conn.Dispose();en bloque finalmente. Pero no veo que la clase esté implementando o heredando la IDisposableinterfaz (SqlConnection clase ), quiero decir. Me pregunto cómo puedo simplemente llamar al nombre del método. También en lo mismo, no entiendo cómo funciona el método Dispose porque necesitamos implementar el cuerpo de la función con nuestra propia implementación para todos los métodos de interfaz. Entonces, ¿cómo se aceptan o nombran las interfaces como contratos? Estas preguntas siguieron rodando en mi mente hasta ahora y, francamente, nunca vi un buen hilo que explicara mis preguntas de una manera que pueda entender.

MSDN, como de costumbre, parece muy aterrador y no hay una sola línea clara allí ( Amigos, disculpen amablemente que están en el desarrollo de alto nivel, creo firmemente que cualquier código o artículo debería llegar a la mente de cualquiera que lo vea, por lo tanto, como muchos otros dicen, MSDN no es de uso ).

El entrevistador dijo:

Tiene 5 métodos y está feliz de implementarlo en la clase directamente, pero si tienes que elegir la clase o interfaz abstracta, ¿cuál eliges y por qué? Le respondí todas las cosas que leí en varios blogs diciendo ventajas y desventajas tanto de la clase abstracta como de la interfaz, pero él no está convencido, está tratando de entender "Por qué la interfaz" en general. "Por qué la clase abstracta" en general, incluso si puedo implementar los mismos métodos solo una vez y no voy a cambiarlo.

No veo ningún lugar en la red, podría conseguir un artículo que me explicara claramente sobre las interfaces y su funcionamiento. Soy uno de esos muchos programadores, que todavía no sé de interfaces (sé teóricos y métodos que utilicé) pero no estoy satisfecho de haberlo entendido con claridad.


4
Las interfaces también son algo que me ha costado entender. Buena pregunta.
Brian

4
programación a un contrato abstracto en lugar de una implementación concreta ... En resumen, significa que puede sustituir cualquier objeto que implemente una interfaz cuando se requiere una interfaz.
Mitch Wheat

7
SqlConnectionhereda lo System.ComponentModel.Componentque implementa IDisposable.
Lee

2
@MitchWheat: no pretende ser un ejemplo, la pregunta es cómo se SqlConnectionimplementa IDisposable.
Lee

Oh, Lee, eso me hizo entender gracias. Pero todavía no veo cómo o dónde se define la funcionalidad del método "Dispose".
Estudiante

Respuestas:


92

Las interfaces son excelentes cuando quieres crear algo como esto:

using System;

namespace MyInterfaceExample
{
    public interface IMyLogInterface
    {
        //I want to have a specific method that I'll use in MyLogClass
        void WriteLog();       
    }

    public class MyClass : IMyLogInterface
    {

        public void WriteLog()
        {
            Console.Write("MyClass was Logged");
        }
    }

    public class MyOtherClass : IMyLogInterface
    {

        public void WriteLog()
        {
            Console.Write("MyOtherClass was Logged");
            Console.Write("And I Logged it different, than MyClass");
        }
    }

    public class MyLogClass
    {
        //I created a WriteLog method where I can pass as a parameter any object that implements IMyLogInterface.
        public static void WriteLog(IMyLogInterface myLogObject)
        {
            myLogObject.WriteLog(); //So I can use WriteLog here.
        }
    }

    public class MyMainClass
    {
        public void DoSomething()
        {
            MyClass aClass = new MyClass();
            MyOtherClass otherClass = new MyOtherClass();

            MyLogClass.WriteLog(aClass);//MyClass can log, and have his own implementation
            MyLogClass.WriteLog(otherClass); //As MyOtherClass also have his own implementation on how to log.
        }
    }
}

En mi ejemplo, yo podría ser un desarrollador que escribe MyLogClass, y los otros desarrolladores podrían crear sus clases y, cuando quisieran iniciar sesión, implementaron la interfaz IMyLogInterface. Es como si me preguntaran qué necesitan implementar para usar el WriteLog()método MyLogClass. La respuesta la encontrarán en la interfaz.


3
Hey que parece un ingrediente muy bueno para mí entender, se lo agradezco mucho, muchas gracias :) :)
Estudiantes de

14
Mi pregunta es si está creando una instancia MyClassy MyOtherClasspor qué no llamaría simplemente aClass.WriteLog()por qué agregar ese paso adicional. La implementación de WriteLog()seguiría siendo diferente para cada una de las clases, pero ya tiene el objeto, entonces, ¿por qué pasarlo a una clase de controlador?
Zach M.

Hm podría ser que si pones tu ejemplo de registro en nugget, sería más simple para otros usar tu registrador, sin conocer los detalles ... pero por otro lado, todavía no es una clase universal, (por ejemplo, podría escribir un interfaz con registro Y todos los niveles) las interfaces todavía están solo dentro de su alcance. así que además de ti, ¿quién se está beneficiando?
user3800527

2
@ZachM. Si estoy en lo cierto, la respuesta significa que no instanciará las clases, pero otros desarrolladores instanciarán las clases y las pasarán como parámetro a MyLogClass WriteLogmétodo. Entonces su método puede manejar cualquier objeto que implemente IMyLogInterface. Aquí hay otra publicación interesante.
shaijut

1
Mi pregunta es ¿por qué Interface ??? El escenario anterior también se puede lograr mediante una clase abstracta con todos los métodos abstractos.
Abhijit Ojha

52

Una de las razones por las que uso interfaces es porque aumenta la flexibilidad del código. Digamos que tenemos un método que toma un objeto del tipo de clase Cuenta como parámetro, como por ejemplo:

public void DoSomething(Account account) {
  // Do awesome stuff here.
}

El problema con esto es que el parámetro del método está fijo hacia la implementación de una cuenta. Esto está bien si nunca necesita ningún otro tipo de cuenta. Tome este ejemplo, que en su lugar utiliza una interfaz de cuenta como parámetro.

public void DoSomething(IAccount account) {
  // Do awesome stuff here.
}

Esta solución no está fijada hacia una implementación, lo que significa que puedo pasarle una SuperSavingsAccount o una ExclusiveAccount (ambas implementando la interfaz IAccount) y obtener un comportamiento diferente para cada cuenta implementada.


45

Las interfaces son contratos que los implementadores deben seguir. Las clases abstractas permiten contratos más implementaciones compartidas, algo que las interfaces no pueden tener. Las clases pueden implementar y heredar múltiples interfaces. Las clases solo pueden extender una única clase abstracta.

Por qué Interface

  • No tiene implementación de código predeterminado o compartido
  • Quiere compartir contratos de datos (servicios web, SOA)
  • Tiene diferentes implementaciones para cada implementador de interfaz ( IDbCommandtiene SqlCommandy OracleCommandque implementan la interfaz de formas específicas )
  • Quieres admitir herencia múltiple .

Por qué abstracto


2
@Silver Leí la mayor parte de lo que escribiste en blogs, pero estoy tratando de entenderlo prácticamente. He realizado servicios WCF, interfaces expuestas (pero era solo una aplicación independiente sin flujo ascendente ni descendente). Por lo tanto, no pude entenderlo correctamente, aunque diseñé e implementé muy bien las interfaces. Mi pregunta es, prácticamente, solo comparte los nombres de los métodos que el contrato significa, ¿verdad? ¿CÓMO ES ÚTIL ESTO :( Sé que solo obliga a implementar todos los métodos, pero de lo contrario cómo? En su publicación anterior sobre la interfaz, el segundo punto dice compartir, significa que puede dar un ejemplo práctico en tiempo real de esto
Aprendiz

1
Para obtener un ejemplo práctico sobre interfaces y SOA, compartimos nuestras Interfaces WCF ( DataContracts) en un ensamblado .NET ( por ejemplo, Contracts.Shared.dll ) para que los consumidores de clientes .NET puedan interoperarChannelFactory fácilmente usando ( evitando generar código a través de Agregar referencia de servicio, etc. ) o usando Agregar referencia de servicio con tipos compartidos
SliverNinja - MSFT

Si declararé solo métodos abstractos dentro de una calss abstracta, entonces la clase abstracta actuará como interfaz, entonces ¿por qué necesitamos una interfaz?
Abhijit Ojha

25

ingrese la descripción de la imagen aquí

Entonces, en este ejemplo, PowerSocket no sabe nada más sobre los otros objetos. Todos los objetos dependen de la energía proporcionada por 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 entre sí.


Esto tiene sentido, pero todavía estoy luchando por entender, ¿podría simplemente no crear una clase base para PowerSocket y todas esas otras cosas heredarla si es necesario? Técnicamente, Power Sockets no tiene idea de las otras clases.
altaaf.hussein

Creo que debido a que la herencia múltiple no está permitida en C #
Hugh Seagraves

22

En una palabra, ¡debido al polimorfismo !

Si "Programa en una interfaz, no en una implementación", puede inyectar diferentes objetos que comparten la misma interfaz (tipo) en el método como argumento. De esta manera, el código de su método no se combina con ninguna implementación de otra clase, lo que significa que siempre está abierto para trabajar con objetos recién creados de la misma interfaz. (Principio de apertura / cierre)

  • Mire en Inyección de dependencias y lea definitivamente Patrones de diseño: elementos de software orientado a objetos reutilizable de GOF.

4

C # no tiene escritura pato: solo porque sepa que un determinado método se implementa en un conjunto de clases concretas no significa que pueda tratarlas de todos modos con respecto a la llamada a ese método. La implementación de una interfaz le permite tratar todas las clases que la implementan como el mismo tipo de cosa, con respecto a lo que define esa interfaz.


3
Puede obtener una especie de tipo pato en .net4 con el tipo dinámico.
Tony Hopkinson

4

Creo que ya se derramó mucha sangre al hacer estas preguntas, y muchos intentan resolver estos problemas explicando términos robóticos que ningún ser humano normal puede entender.

Así que primero. para saber por qué la interfaz y por qué abstractas, debes saber para qué sirven. Personalmente aprendí estos dos al aplicar Factory Class. encuentras un buen tuturial en este enlace

Ahora profundicemos en el enlace que ya di.

Tiene una clase de vehículo que puede cambiar según los requisitos del usuario (como agregar camión , tanque , avión , etc.).

public class clsBike:IChoice
{
   #region IChoice Members
    public string Buy()
    {
       return ("You choose Bike");
    }
    #endregion
}

y

public class clsCar:IChoice
{
   #region IChoice Members
    public string Buy()
    {
       return ("You choose Car");
    }
    #endregion
}

y ambos tienen un contrato IChoice que simplemente dice que mi clase debería tener el método de compra

public interface IChoice
{
    string Buy();
}

Ahora, verá, esa interfaz solo aplica el método, Buy()pero deja que la clase heredada decida qué hacer cuando lo implemente. Esta es la limitación de Interface, usando puramente interface, podrías terminar repitiendo alguna tarea que podemos implementar automáticamente usando abstact. En nuestro ejemplo, digamos, comprar cada vehículo tiene un descuento.

public abstract class Choice
{
    public abstract string Discount { get; }
    public abstract string Type { get; }
    public string Buy()
    {
       return "You buy" + Type + " with " + Discount;
}
public class clsBike: Choice
{
    public abstract string Discount { get { return "10% Discount Off"; } }
    public abstract string Type { get { return "Bike"; } }
}

public class clsCar:Choice
{
    public abstract string Discount { get { return " $15K Less"; } }
    public abstract string Type { get { return "Car"; } }
}

Ahora, usando Factory Class, puede lograr lo mismo, pero al usar abstract, deja que la clase base ejecute el Buy()método.

En resumen: los contratos de interfaz permiten que la clase heredada realice la implementación, mientras que los contratos de la clase abstracta pueden inicializar la implementación (que puede anular la clase heredada)


2

Con una interfaz puede hacer lo siguiente:

1) Cree interfaces segregadas que ofrezcan diferentes cortes de su implementación, lo que permite una interfaz más cohesiva.

2) Permita múltiples métodos con el mismo nombre entre interfaces, porque bueno, no tiene una implementación conflictiva, solo una firma.

3) Puede versionar y separar su interfaz independientemente de su implementación, asegurando que se cumpla un contrato.

4) Su código puede depender de la abstracción en lugar de la concreción, lo que permite la inyección de dependencia inteligente, incluida la inyección de Mocks de prueba, etc.

Estoy seguro de que hay muchas más razones, estas son solo algunas.

Una clase abstracta le permite tener una base parcialmente concreta para trabajar, esto no es lo mismo que una interfaz pero tiene sus propias cualidades, como la capacidad de crear una implementación parcial usando el patrón del método de plantilla.


Olvidaste lo más importante: implementar una interfaz hace que tu clase sea utilizable por cualquier código que necesite una implementación de esa interfaz, sin que el código en cuestión tenga que saber nada sobre tu clase.
supercat

2

Como muestra real de la respuesta de @ user2211290:

Ambos de Arrayy Listtienen interfaz IList. A continuación tenemos un string[]y un List<string>y los verificamos con un método usando IList :

string[] col1 = { "zero", "one", "two", "three", "four"};
List<string> col2 = new List<string>{ "zero", "one", "two", "three"};

//a methode that manipulates both of our collections with IList
static void CheckForDigit(IList collection, string digit)
{
    Console.Write(collection.Contains(digit));
    Console.Write("----");
    Console.WriteLine(collection.ToString()); //writes the type of collection
}

static void Main()
{
    CheckForDigit(col1, "one");   //True----System.String[]
    CheckForDigit(col2, "one");   //True----System.Collections.Generic.List`1[System.String]



//Another test:

    CheckForDigit(col1, "four");   //True----System.String[]
    CheckForDigit(col2, "four");   //false----System.Collections.Generic.List`1[System.String]
}

1

Solo puede heredar de una clase abstracta. Puede heredar de múltiples interfaces. Esto determina lo que uso para la mayoría de los casos.

La ventaja de la clase abstracta sería que puede tener una implementación base. Sin embargo, en el caso de IDisposable, una implementación predeterminada es inútil, ya que la clase base no sabe cómo limpiar adecuadamente las cosas. Por tanto, una interfaz sería más adecuada.


1

Tanto la clase abstracta como la interfaz son contratos.

La idea de un contrato es que especifiques algún comportamiento. Si dice que ha implementado, ha aceptado el contrato.

La elección de abstracto sobre interfaz es.

Cualquier descendiente no abstracto de la clase abstracta implementará el contrato.

versus

Cualquier clase que implemente la interfaz implementará el contrato.

Por lo tanto, usa abstracto cuando desea especificar algún comportamiento que todos los descendientes deben implementar y ahorrarse la definición de una interfaz separada, pero ahora todo lo que cumple con este contrato agregado de manera efectiva debe ser un descendiente.


1

Las interfaces son para hacer una abstracción (un arquetipo) de la abstracción (las clases) de la realidad (los objetos).

Las interfaces deben especificar los términos del contrato sin proporcionar la implementación proporcionada por las clases.

Las interfaces son especificaciones:

  • Las interfaces son artefactos de tiempo de diseño para especificar el comportamiento inmóvil del concepto, ya que es solo y estático.

  • Las clases son artefactos de tiempo de implementación para especificar la estructura móvil de la realidad a medida que interactúa y se mueve.

¿Qué es una interfaz?

Cuando observas a un gato puedes decir que es un animal que tiene cuatro patas, una cabeza, un tronco, una cola y pelo. Puedes ver que puede caminar, correr, comer y maullar. Y así.

Acaba de definir una interfaz con sus propiedades y sus operaciones. Como tal, no ha definido ningún modus operandi, sino solo características y capacidades sin saber cómo funcionan las cosas: ha definido habilidades y distinciones.

Como tal, todavía no es una clase, aunque en UML la llamamos clase en un diagrama de clases porque podemos definir miembros privados y protegidos para comenzar a tener una visión profunda del artefacto. No se confunda aquí porque en UML una interfaz es algo ligeramente diferente a una interfaz en C #: es como un punto de acceso parcial al átomo de abstracción. Como tal, dijimos que una clase puede implementar múltiples interfaces. Como tal, es lo mismo, pero no, porque las interfaces en C # se usan para abstraer la abstracción y para limitar esta abstracción como un punto de acceso. Son dos usos diferentes. Así, una clase en UML representa una interfaz de acoplamiento completo a una clase de programación, mientras que una interfaz UML representa una interfaz de desacoplamiento de una sección de una clase de programación. En efecto, el diagrama de clases en UML no se ocupa de la implementación y todos sus artefactos están al nivel de la interfaz de programación. Si bien asignamos clases UML a clases de programación, es una transposición de abstracción abstracta a abstracción concreta. Hay una sutileza que explica la dicotomía entre el campo del diseño y el campo de la programación. Entonces, una clase en UML es una clase de programación desde el punto de vista de una interfaz de programación considerando cosas internas ocultas.

Las interfaces también permiten simular herencia múltiple cuando no está disponible de una manera incómoda. Por ejemplo, la clase cat implementará la interfaz cat que se deriva de la interfaz animal. Esta clase de gato también implementará estas interfaces: caminar, correr, comer y hacer un sonido. Esto compensa la ausencia de herencia múltiple a nivel de clase, pero cada vez necesitas reimplementar todo y no puedes factorizar la realidad en el mejor de los casos como lo hace la realidad misma.

Para entender eso podemos referirnos a la codificación de objetos Pascal donde se define en una unidad la interfaz y las secciones de implementación. En la interfaz se definen los tipos y en la implementación se implementa el tipo:

unit UnitName;

interface

type
  TheClass = class
  public
    procedure TheMethod;
  end;

implementation

class procedure TheClass.TheMethod;
begin
end;

Aquí, la sección de interfaz coincide con el diseño de la clase UML, mientras que los tipos de interfaces son, por lo tanto, otras cosas.

Entonces, en nuestro negocio tenemos una palabra, interfaz , para nombrar dos cosas distintas pero similares, y es una fuente de confusión.

También en C #, por ejemplo, las interfaces de programación permiten compensar la ausencia de polimorfismo genérico verdadero en tipos abiertos sin realmente tener éxito en el objetivo porque perdió la habilidad fuertemente tipada.

Después de todo, las interfaces son necesarias para permitir que los sistemas incompatibles se comuniquen sin preocuparse por la implementación y la gestión de los objetos en la memoria como se introdujo con el Modelo de Objetos Comunes (Distribuido).

¿Qué es una clase?

Después de definir una reducción de la realidad desde un punto de vista externo, puedes describirla desde una perspectiva interna: esta es la clase en la que defines el procesamiento de datos y la gestión de mensajes para permitir que la realidad que has encapsulado cobre vida e interactúe gracias a los objetos que utilizan instancias.

Entonces en UML realizas una inmersión fractal en las ruedas de la maquinaria y describes los estados, las interacciones y así sucesivamente para poder implementar la abstracción del fragmento de la realidad que quieres manejar.

Como tal, una clase abstracta es de alguna manera el equivalente de una interfaz desde el punto de vista del compilador.

Más información

Protocolo (programación orientada a objetos)

C #: interfaces

C # - Clases


1

Déjame contarte sobre las tostadoras voladoras.

tostadora voladora

Hay, por supuesto, muchas situaciones en las que puede construir un sistema de software que funcione sin declarar o implementar ninguna interfaz: cualquier diseño de software orientado a objetos se puede realizar utilizando nada más que clases.

Por otra parte, cualquier sistema de software también se puede implementar en lenguaje ensamblador o, mejor aún, en código máquina. La razón por la que usamos mecanismos de abstracción es porque tienden a facilitar las cosas. Las interfaces son un mecanismo de abstracción.

Entonces, da la casualidad de que hay ciertos diseños orientados a objetos no triviales que son mucho más fáciles de implementar si usa interfaces, que las interfaces prácticamente se vuelven necesarias en esos casos.

Estos diseños no triviales tienen que ver con la herencia múltiple, que, en su forma "verdadera", es cuando una clase hereda no solo de una clase base, sino de dos o más clases base. Esta forma verdadera no es posible en C #, pero antes de que aparecieran lenguajes como C # y Java, el lenguaje que gobernaba era C ++, que es totalmente compatible con la verdadera herencia múltiple. Desafortunadamente, la verdadera herencia múltiple resultó no ser una muy buena idea, porque complica enormemente el diseño del lenguaje, y también da lugar a varios problemas, por ejemplo el famoso "Problema del Diamante". (Ver "¿Cuál es el problema exacto con la herencia múltiple?" Respuesta de J Francis )

Entonces, si alguien quisiera construir una clase de "tostadora voladora", heredaría de alguna clase de "tostadora" existente y también de alguna clase "voladora" existente. El tipo de problema con el que probablemente se encontraran era que la fuente de alimentación de la clase tostadora probablemente sería un enchufe de pared, mientras que la fuente de alimentación de la clase de máquinas voladoras probablemente sería comida para palomas, y la nueva clase resultante podría ser de alguna manera tener ambos, o no estaría claro cuál tendría. (El problema del diamante).

Los creadores de lenguajes como C # y Java decidieron no permitir la verdadera herencia múltiple, con el fin de mantener el lenguaje simple y evitar trampas como el problema del diamante. Sin embargo, todavía es necesaria alguna forma de herencia múltiple (o al menos muy deseable), por lo que en estos lenguajes introdujeron interfaces como un medio para admitir una forma menor de herencia múltiple evitando los problemas y la complejidad de la verdadera herencia múltiple.

En esta forma menor de herencia múltiple, no se le permite tener una clase que herede de más de una clase base, pero al menos puede heredar de una o más interfaces. Entonces, si desea construir una tostadora voladora, no puede heredar tanto de alguna clase de tostadora existente como de alguna clase voladora existente, pero lo que puede hacer es heredar de una clase de tostadora existente y luego también exponer una interfaz de vuelo que usted mismo implementa. posiblemente utilizando cualquier medio que ya haya heredado de la tostadora.

Por lo tanto, a menos que alguna vez sienta la necesidad de crear una clase que agregue dos conjuntos de funcionalidad diferentes y no relacionados, no necesitará ninguna forma de herencia múltiple, por lo que no necesitará declarar o implementar ninguna interfaz.


0

Las interfaces permiten al diseñador de clases dejar muy claros los métodos disponibles para el usuario final. También son una parte integral del polimorfismo.


Bien dicho en su primera declaración. Pero no entiendo su segunda declaración, ¿podría elaborar con un ejemplo en tiempo real, por favor?
Estudiante

0

No publicaré la definición de una interfaz en una clase abstracta porque creo que conoces muy bien la teoría y supongo que conoces los principios SOLID, así que seamos prácticos.

Como sabe, las interfaces no pueden tener ningún código, por lo que las ventajas son bastante sencillas de entender.

si necesita inicializar la propiedad de su clase proporcionando un constructor o si desea proporcionar parte de la implementación, una clase abstracta sería una buena opción contra una interfaz que no le permitiría hacer eso.

Entonces, en general, debe preferir la clase abstracta a las interfaces cuando necesite proporcionar un constructor o cualquier código al cliente que heredará / extenderá su clase


-2

La clase abstracta se crea para entidades relacionadas, donde las interfaces se pueden usar para entidades no relacionadas.

Por ejemplo, si tengo dos entidades que dicen Animal y Human, iré a Interface donde, como si tuviera que ir en detalle, digamos Tiger, lion y quiero relacionarme con Animal, entonces elegiré la clase Animal Abstract.

se verá como a continuación

   Interface             
   ____|____
  |        |
Animal   Human



  Animal (Abstract class)
   __|___
  |      |
Tiger   Lion
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.