¿Cuándo debería uno usar interfaces?

Sé que una interfaz no tiene un cuerpo simplemente una definición de método. ¿Pero cuándo debería usar interfaces? Si proporciono a alguien un conjunto de interfaces sin cuerpo, ¿por qué sentirían la necesidad de escribir el cuerpo de la función? ¿Sería mejor escribir su propia clase abstracta con métodos abstractos en ella?

Editado:

Supongo que el uso de interfaces es más cuando formas parte de un equipo. Supongamos que el Equipo A escribe un código para algo y querían ver si se llama a un método. con el nombre getRecords (), está hecho o no. Esto ayudará al Equipo B a escribir el cuerpo de la interfaz que se les proporciona y el Equipo B tiene que mantener el nombre del método similar para que se ejecute el código del Equipo A.

Solo un pensamiento. Podría estar equivocado. Creo que las interfaces no tienen uso para un solo desarrollador.

Editado:

Gracias por todas las respuestas. Con lo que todos ustedes han respondido, creo que las interfaces tienen más uso cuando están haciendo algo como API.

En lenguajes como las interfaces Java y C # proporcionan un medio para que una clase se tenga de forma polimórfica . Es decir, una clase puede satisfacer más de un contrato; puede comportarse como múltiples tipos diferentes, una clase de un tipo puede sustituirse por otra. En otros idiomas, esto también puede ser proporcionado por herencia múltiple , pero este enfoque tiene varias desventajas. Sin embargo, hacer que una clase se comporte como más de un tipo no es la motivación más común para usar interfaces.

Al progtwigr interfaces en lugar de clases, también puede desacoplar su progtwig de implementaciones específicas. Esto hace que sea mucho más fácil sustituir una implementación de clase por otra. Esto es particularmente útil cuando se escriben pruebas unitarias donde es posible que desee cambiar alguna implementación de clase pesada con un objeto simulado liviano. Si su progtwig solo espera un tipo de interfaz, y tanto el objeto pesado como el objeto simulado implementan dicha interfaz, entonces son muy fáciles de sustituir.

Además, considere un ejemplo simple de Java donde digo que tiene un progtwig que muestra páginas de datos en la pantalla. Inicialmente quiero que obtenga los datos de una base de datos o archivos XML. Si escribo mi progtwig para que use interfaces, puedo definir una interfaz como esta:

 public interface PageDatasource { public List getPages(); } 

Y úsalo así:

 PageDatasource datasource = // insert concrete PageDatasource implementation here List pages = datasource.getPages(); display(pages); 

Luego puedo escribir bases de datos separadas e implementaciones XML que se adhieren a esta interfaz:

 public class DatabasePageDatasource implements PageDatasource { public List getPages() { // Database specific code } } public class XmlPageDatasource implements PageDatasource { public List getPages() { // XML specific code } } 

Debido a que utilicé una interfaz, ahora puedo usar cualquiera de las implementaciones – Base de datos o XML – indistintamente sin tener que cambiar las partes de mi progtwig que solicitan los datos de la página. Las implementaciones de XML y de base de datos probablemente hacen cosas completamente diferentes, pero lo único que le importa a mi progtwig es que el objeto que suministra los datos de la página implemente la interfaz de PageDatasource .

Interfaz de la vida real analogía:

Supongamos que quiere emitir un libro desde la biblioteca. Qué harás:
1) Ir a la biblioteca
2) Encuentra el libro que te interesa
3) Seleccione el libro
4) Diríjase a la Mesa de Bibliotecarios para solicitar que emita el Libro.

Ahora, aquí, Bibliotecario es una interfaz, lo que significa que no está interesado en quién diablos es bibliotecario, solo le interesa esa persona sentada en el escritorio de la biblioteca (es la persona que aceptó un contrato para actuar como bibliotecario, lo que significa que esa persona estuvo de acuerdo para implementar todos los comportamientos de bibliotecario)

Así que vamos a decir : Comportamiento de bibliotecario son:
1) Libro de publicaciones
2) Libro de reemisión
3) Libro de devolución.
la persona designada como bibliotecario (lo que significa que acordó adaptar los tres comportamientos anteriores) debe implementar los comportamientos a su manera.

Digamos que PersonA quiere ser parte de Bibliotecario, luego debe adaptar los 3 Comportamientos anteriores. A nosotros, como cliente, no nos importa cómo está desempeñando sus comportamientos de bibliotecario, solo nos interesa esa persona. Es bibliotecario y cumple las tareas de bibliotecario.
Por lo tanto, lo que harás es referencia por interfaz [ve al escritorio del bibliotecario (que te llevará a las personas que actúan como bibliotecario)] y di en futuro una persona que dejó el puesto de bibliotecario, luego como cliente no te afectará si se han acercado al mostrador del bibliotecario , en lugar de a una persona específica que actúa como bibliotecario . Por lo tanto, el código para la interfaz en lugar de la especificidad es beneficioso.

 class PersonA implements Librarian { public void IssueBook(){...} public void ReIssueBook(){...} public void ReturnBook(){...} //Other person related tasks... } 

Incluso como interfaces de desarrollador único puede ser una herramienta muy útil. Déjame intentar ilustrar con un ejemplo.

Supongamos que está desarrollando un sistema para administrar un catálogo de biblioteca y que la biblioteca prestará libros y DVD. Decide crear clases Libro y DVD para modelar los elementos que se prestan, pero ahora desea implementar polymorphism para que pueda tratar con elementos en lugar de libros o DVD. La pregunta es si el artículo debe ser una clase abstracta o una interfaz.

En esta instancia, es probable que desee utilizar una clase abstracta, ya que existe una funcionalidad común tanto para el libro como para el DVD que puede proporcionar una clase principal, por ejemplo, retirar o devolver un artículo.

Ahora supongamos que desea implementar un mecanismo de persistencia para su catálogo de biblioteca. Ha decidido que desea almacenar algunos datos en una base de datos, algunos datos en archivos XML y algunos datos en archivos delimitados por comas. Entonces, la pregunta ahora es ¿cómo puedes hacer esto de una forma polimórfica que te permite manejar una API de persistencia general?

En este caso, probablemente debas definir una interfaz que pueda implementar cada una de tus clases proporcionando la base de datos, XML y persistencia delimitada por comas, ya que cada uno de estos mecanismos de persistencia proporciona características similares, es decir, almacenar y recuperar datos, pero cada uno se implementará de manera muy diferente. Esto le permitirá cambiar fácilmente el mecanismo de persistencia que está utilizando sin tener que realizar muchos cambios en el código que usa el mecanismo de persistencia.

Las interfaces ayudan a aclarar la distinción entre diferentes unidades funcionales. Una unidad depende de otra unidad para hacer algo, no para ser algo. Mientras ese otro pueda hacer lo que está estipulado en la interfaz ( contrato de pensar), puede ser cualquier cosa detrás de escena.

Por ejemplo, tengo un procesador de entrada que lee entradas de un lugar y las escribe en otro lugar. No le importa de qué / dónde, ni a qué / dónde. Lo único que importa es que está obteniendo la entrada de algún tipo de lector (usando la interfaz IReader ) en un lado, y entregándoselos a algún tipo de escritor (usando la interfaz IWriter ).

En mi primera implementación, el implementador de IReader obtiene material de una base de datos SQL, y el implementador de IWriter lo publica a través de un cliente de servicio web. Sin embargo, eventualmente crearemos otros implementadores en cada extremo para acceder a otros repositorys (sitios FTP, directorios de archivos en una unidad de red local, etc.).

Todo este tiempo al procesador en el medio no le importa y no cambia. Simplemente habla a través de esas interfaces estándar.

Teóricamente podría usar una clase base (preferiblemente una abstracta ) en lugar de una interfaz, pero eso comienza a bloquear más estrechamente sus módulos, lo que hace que su sistema sea más difícil de mantener. Lose coupling realmente te hace la vida más fácil, incluso si no estás en un equipo de progtwigdores. Considérese un progtwigdor diferente cada vez que trabaje en una parte diferente de su sistema. Cada vez que vuelves a visitar una sección determinada, debes volver a aprender lo que hace para mantenerla. Si cada pieza de su sistema está estrechamente unida a cualquier otra pieza, debe tener un conocimiento constante e íntimo de todo el sistema, no solo de la pieza en la que está trabajando.

También existe el concepto de una sola clase que implementa múltiples interfaces, que es casi como una herencia múltiple. En esta situación, una sola clase puede realizar múltiples trabajos (lo que puede argumentarse no es muy inteligente, pero al menos es posible). Si elige usar una clase base en lugar de una interfaz anterior, entonces esto no sería posible.

A primera vista, las clases e interfaces abstractas parecen obvias. ¿Por qué proporcionar solo una interfaz cuando también puede proporcionar una implementación básica? Después de la investigación, encontrarás que hay más en esto.

Dicho esto, hay varias razones para usar interfaces. Puede encontrar una entrada decente en el blog sobre las diferencias aquí .

Dicho esto, considere el hecho de que puede crear una interfaz (un “contrato” que dice que su clase definitivamente admite ciertas llamadas / invocaciones de firmas de métodos), pero solo puede proporcionar una clase abstracta única. Considere también el hecho de que puede crear una clase abstracta que también implemente una o varias interfaces y heredar de esta. Esto no es un caso marginal. En realidad, esto se hace con bastante frecuencia en las API para gran extensibilidad.

Revisa la publicación del blog que te indiqué y deberías obtener una comprensión completa de cuándo usar cada uno y por qué los usarías. También recomendaría un buen libro como “CLR via C #” de Microsoft Press. ¡Aprenderás mucho!

La razón por la que existen interfaces se debe a los 2 conceptos principales de OOP, que es “identidad” y “funcionalidad”

Las clases tienen funcionalidad e identidad. Con la herencia, los objetos instanciados pueden tener mucha funcionalidad e identidades múltiples.

Las interfaces son una identidad sin funcionalidad. La funcionalidad será proporcionada por la clase instanciada.

La tercera forma, una “mezcla” es la funcionalidad sin identidad. Los lenguajes de progtwigción como Ruby proporcionan esta tercera forma de herencia.

La forma en que utiliza una interfaz difiere según el contexto de su lenguaje de progtwigción y sus circunstancias, pero recuerde que las interfaces se utilizan para definir identidades que se aplican a los objetos.

Para agregar a las respuestas anteriores, las interfaces lo ayudan durante las pruebas unitarias al permitirle insertar un objeto simulado basado en una interfaz en su código, lo que le permite simular escenarios específicos y aislar su prueba unitaria a un componente específico sin depender de componentes externos .

Por ejemplo, supongamos que tiene una clase de lógica de negocios que usa una clase de lógica de datos para recuperar datos de una fuente de datos y luego procesarlos. Al crear una interfaz para la clase de lógica de datos que luego hereda, puede crear una instancia falsa / falsa de esa clase basada en la interfaz e inyectarla en la clase de lógica de negocios que está probando en unidades. La instancia simulada se puede definir para esperar ciertas llamadas al método / propiedad, lanzar excepciones en ciertos puntos, devolver resultados válidos, etc. Esto significa que las pruebas de su unidad pueden ejecutarse de manera más rápida / potencialmente más confiable ya que no dependen de los datos subyacentes la fuente está disponible / en realidad no tiene que conectarse a ella. Y estás aislando la prueba unitaria en una unidad específica de código.

Una interfaz es mejor que una clase abstracta porque puede implementar múltiples interfaces y solo puede heredar de una clase abstracta.

Entonces puedes hacer:

 class MyRow extends AbstractRow implements ISearchable, ISortable { } 

Además, busque StackOverflow para otras preguntas similares como Need of interfaces in c #

Las interfaces y las clases abstractas tienen diferentes propósitos. Para empezar, una clase abstracta solo sirve para heredar, no se puede crear una instancia directamente. Puede poner el código de implementación en una clase abstracta, pero ese código solo puede invocarse desde la clase que lo extiende o mediante la clase que lo extiende.

ejemplo:

 public abstract class A { public void myFunc() { //do some work } } public class B : A { private void someOtherFunc() { base.myFunc(); } } public class Z { public void exampleFunc() { //call public base class function exposed through extending class: B myB = new B(); myB.myFunc(); //explicitly cast B to A: ((A) myB).myFunc(); //'A' cannot be created directly, do implicit cast down to base class: A myA = new B(); myA.myFunc(); } } 

El objective de una interfaz es proporcionar un contrato ; esto significa que la clase que lo implemente debe proporcionar la implementación de las propiedades o funciones declaradas en la interfaz, y debe usar exactamente las mismas firmas de funciones. Esto proporciona seguridad cuando escribo un código que llama a una clase que implementa una interfaz, y es irrelevante de qué se derivan las clases, o incluso en qué idioma están escritas, o de dónde las obtuve. Otra característica interesante es que puedo tener varias implementaciones diferentes de la misma firma de función para diferentes interfaces. Verifique este ejemplo, que utiliza algunas de las mismas clases de la muestra anterior:

 public class Z { public void exampleFunc() { C myC = new C(); //these two calls both call the same function: myC.myFunc(); ((IExampleInterface1)myC).myFunc(); D myD = new D(); //hmmm... try and work out what happens here, which myFunc() gets called? //(clue: check the base class) myD.myFunc(); //call different myFunc() in same class with identical signatures: ((IExampleInterface1)myD).myFunc(); ((IExampleInterface2)myD).myFunc(); } } interface IExampleInterface1 { void myFunc(); } interface IExampleInterface2 { void myFunc(); } public class C : IExampleInterface1 { public void myFunc() { //do stuff } } public class D : A, IExampleInterface1, IExampleInterface2 { void IExampleInterface1.myFunc() { //this is called when D is cast as IExampleInterface1 } void IExampleInterface2.myFunc() { //this is called when D is cast as IExampleInterface2 } } 

Es un problema de diseño (hablo del mundo java).

La interfaz le permite definir el comportamiento y la estructura del componente (clase) de su software sin darle restricciones en el tiempo de ejecución.

La clase abstracta, en cambio, le proporciona un comportamiento predeterminado para un método: útil si está seguro de que este código podría no cambiar en el momento de la aplicación.

Ejemplo:

Usted tiene una aplicación web del sistema comercial que envía un correo electrónico en alguna situación (registro de un nuevo usuario).

Puede usar la clase abstracta SenderCommunication con el método boolean sendWithSuccefull (…) si está seguro de que el comportamiento no cambiará detern.

Puede usar la interfaz InterfaceSenderCommunication con el método boolean sendWithSuccefull (…) si no está seguro de que el comportamiento no cambiará a menudo.

Por supuesto, el criterio de “cambiar a menudo, no a menudo” depende de 2 elementos:

  • ¿Cuánto tiempo debo dedicar para sincronizar el código anterior con las nuevas especificaciones?
  • ¿Cuánto paga el cliente? 😉

Supongamos que tengo FoodEstablishment de la clase, ahora quiero hacer una operación CRUD simple, entonces ¿cómo lo hago? Defino una interfaz para el servicio, pero ¿por qué?

 public interface IFoodEstablishmentService { Task AddAsync(FoodEstablishment oFoodEstablishment); FoodEstablishment SelectByFoodEstablishmentId(long id); Task UpdateAsync(FoodEstablishment oFoodEstablishment); Task DeleteAsync(FoodEstablishment oFoodEstablishment); } 

Entonces implementaré ese contrato o interfaz para ese servicio en particular

 public class FoodEstablishmentService : IFoodEstablishmentService { public async Task AddAsync(FoodEstablishment oFoodEstablishment) { // Insert Operation return result; } public FoodEstablishment SelectByFoodEstablishmentId(long id) { // Select Logic return oFoodEstablishment; } public async Task UpdateAsync(FoodEstablishment oFoodEstablishment) { // Update Logic return result; } public async Task DeleteAsync(FoodEstablishment oFoodEstablishment) { // Delete Logic return result; } } 

Entonces, en mi progtwig principal o en el que deseo usar el Servicio, lo haré

 IFoodEstablishmentService oFoodEstablishmentService = new FoodEstablishmentService(); FoodEstablishment oFoodEstablishment = // Input might be from views; oFoodEstablishmentService.AddAsync(oFoodEstablishment); 

Hasta ahora parece un paso extra, cuando podríamos haberlo hecho directamente

 FoodEstablishmentService oFoodEstablishmentService = new FoodEstablishmentService(); FoodEstablishment oFoodEstablishment = // Input might be from views; oFoodEstablishmentService.AddAsync(oFoodEstablishment); 

Pero, ¿qué pasaría si tuviera que pasar mi lógica de inserción a través de la cola en lugar de directamente al servidor, esperar a que finalice la operación de inserción y luego devolver el resultado, pasar la cola y luego el trabajador de la cola manejar esas operaciones, podría no ser la mejor idea Insertar cola pero sí definitivamente bueno para el ejemplo de interfaz :-). Entonces, ahora lo que hago es crear otra clase FoodEstablishment implementando el mismo contrato IFoodEstablishment.

 public class FoodEstablishmentQueueService : IFoodEstablishmentService { public async Task AddAsync(FoodEstablishment oFoodEstablishment) { // Insert Queue Operation return result; } public FoodEstablishment SelectByFoodEstablishmentId(long id) { // Select Queue Logic return oFoodEstablishment; } public async Task UpdateAsync(FoodEstablishment oFoodEstablishment) { // Update Queue Logic return result; } public async Task DeleteAsync(FoodEstablishment oFoodEstablishment) { // Delete Queue Logic return result; } } 

Entonces, si quiero usar la versión de la cola, simplemente lo haría

 IFoodEstablishmentService oFoodEstablishmentService = new FoodEstablishmentQueueService(); FoodEstablishment oFoodEstablishment = // Input might be from views; oFoodEstablishmentService.AddAsync(oFoodEstablishment); 

Podríamos hacer eso usando la clase anterior pero eso limita la creación de instancias de clase con una clase particular que es rígida a la extensión, ahora FoodEstablishmentQueueService puede hacer otras cosas también, crear otro método hasta que el contrato sea válido, así que la interfaz es de coherencia Imagine que un tipo está haciendo la versión normal y otra haciendo la versión en cola o alguien que está haciendo una versión en caché, puede haber problemas con la firma a menos que esté especificado previamente sobre el contrato laboral y la gente no termine revisando todo.

Del mismo modo, consideremos otro ejemplo simple de uso de tipos predefinidos como IEnumerable. Supongamos que paso una lista de la colección FoodEstablishment y devuelvo una lista ordenada personalizada

 public FoodEstablishment[] SortFoodEstablishment(FoodEstablishment[] list) { foreach(var oFoodEstablishment in list) { // some logic } return sortedList; } 

Entonces lo usaremos de esta manera

 FoodEstablishment[] list = new FoodEstablishment[]{ //some values } var listSorted = oFoodEstablishmentService.SortFoodEstablishment(list); 

Pero, ¿y si enviamos list en lugar de array?

 List list = //some values; var listSorted = oFoodEstablishmentService.SortFoodEstablishment(list); 

Obtendremos el error, porque su implementación estricta usa la clase, así que en su lugar usamos IEnumerable <> que implementa List y que básicamente elimina la dependencia de List to Interface

 public IEnumerable SortFoodEstablishment(IEnumerable list) { foreach(var oFoodEstablishment in list) { // some logic } return sortedList; } 

Por lo general, la implementación depende enormemente de la situación

Una razón para usar interfaces es cuando una clase implementará una serie de interfaces. Una clase abstracta no puede hacer eso.

Un ejemplo es una clase que maneja el movimiento del mouse y las pulsaciones de teclas implementarán las interfaces (ficticias) IMouseMove e IKeyPress.

Además, el uso de interfaces alivia las pruebas unitarias. Para probar clases que dependen de interfaces, y siempre que esté utilizando algún tipo de dependency injection, puede crear clases de stub que implementan las interfaces dependientes, o puede usar un motor de burla.

Java Lang no es compatible con herencia múltiple ya que las interfaces se utilizan para lograr el objective.

Para que una clase sea abstracta, solo 1 método debe ser abstracto; Mientras que en el caso de la interfaz, todos los métodos son abstractos.

La interfaz de la clase abstracta v / s siempre es un punto de discusión entre los desarrolladores. Yo agregaría mis 5 centavos. Use la clase abstracta cuando desee extender una base de comandantes y en la que desee proporcionar una implementación predeterminada al método abstracto.

Utilice la interfaz cuando desee implementar exactamente todos los métodos abstractos para la clase que implementa la interfaz y no se puede proporcionar un cuerpo predeterminado para un método.

Se considera buen estilo almacenar una referencia a un HashSet o TreeSet en una variable de tipo Set.

Set names = new HashSet();

De esta manera, debe cambiar solo una línea si decide usar un TreeSet en TreeSet lugar.

Además, los métodos que operan en conjuntos deben especificar parámetros de tipo Conjunto:

public static void print(Set s)

Entonces el método se puede usar para todas las implementaciones establecidas.

En teoría, deberíamos hacer la misma recomendación para las listas enlazadas, es decir, para guardar referencias de LinkedList en variables de tipo List. Sin embargo, en la biblioteca de Java, la interfaz de lista es común tanto para la clase ArrayList como para la clase LinkedList . En particular, tiene métodos get y set para el acceso aleatorio, aunque estos métodos son muy ineficientes para las listas enlazadas.

No puede escribir código eficiente si no sabe si el acceso aleatorio es eficiente o no. Esto es claramente un grave error de diseño en la biblioteca estándar, y no puedo recomendar el uso de la interfaz de la lista por ese motivo.

(Para ver qué vergonzoso es ese error, eche un vistazo al código fuente del método binarySearch de la clase Collections. Ese método toma un parámetro List, pero la búsqueda binaria no tiene sentido para una lista vinculada. El código luego intenta torpemente descubrir si la lista es una lista vinculada, y luego cambia a una búsqueda lineal!)

La interfaz Set y la interfaz Map están bien diseñadas, y debe usarlas.

La interfaz mantiene la definición e implementación separadas. Por lo tanto, en caso de que desee una implementación específica del proveedor, esta es la mejor manera de hacerlo.

El ejemplo de la vida real de esto es JDBC. Si ve la API Statemnet, PreparedStatemnet Everything es la interfaz, pero la implementación es específica del proveedor como Oracle ojdbc jar tiene alguna otra implementación, mysql tenía alguna otra.

En caso de que quiera cambiar la base de datos, solo tiene que modificar el controlador nad en el nombre de la clase de conexión. Esta es la ventaja de usar la interfaz

Usos de la interfaz:

  1. Para definir un contrato
  2. Para vincular las clases no relacionadas con tiene una capacidad (por ejemplo, las clases que implementan la interfaz Serializable pueden o no tener ninguna relación entre ellas, excepto la implementación de esa interfaz
  3. Para proporcionar una implementación intercambiable, por ejemplo Strategy_pattern

Si está buscando Java como lenguaje de progtwigción, la interface tiene pocas capacidades más con la adición de métodos default y static desde la versión Java-8.

Consulte esta pregunta para más detalles:

¿Por qué utilizar interfaces, herencia múltiple frente a interfaces, ventajas de las interfaces?

Los objetos que pertenecen a una categoría pueden usar una interfaz. Siempre que exista una relación IS-A entre los objetos.

Eg Text, Image, MP3, FLV, MOV pertenece a la categoría Tipo de archivo

Si nuestra aplicación permite a los usuarios subir 4 tipos de archivos, todos pertenecen a una categoría llamada FILE TYPE

  1. Texto
  2. Imagen
  3. Audio
  4. Vídeo

Dentro del código tendremos un objeto para cada uno de los tipos anteriores.

enter image description here

Supongamos que necesitamos enviar un archivo y luego

Con Out Interface

enter image description here

Con la interfaz

enter image description here

Por lo tanto, podemos suponer que todos los tipos de archivos (texto, audio, etc.) son de tipo FileFormat. Así que formamos una relación IS-A.

Esto ayuda al devolver el tipo de datos individuales en lugar de devolver el tipo específico de una función, podemos enviar un tipo común que sea FileFormat.

enter image description here