Otra pregunta de "¿Por qué usar el Resumen / Interfaz"? Pero soy un desarrollador en solitario. ¿Por qué usarlo?

7

Sé el propósito de eso y todo. Me veo como un desarrollador en solitario por un par de años más.

Siempre veo respuestas que es contrato. Sí, lo entiendo.

Pero hay algo en mi mente:

Si una clase no proporcionó lo que quiere una Interfaz, generará un error.

Bueno, si una clase realmente necesita ese método, lanzará un error aún si hay algo que lo llame y no está ahí, ¿no?

¿Cuál es la diferencia?

Realmente puedo implementarlo e ir de acuerdo con las "normas", pero eso me dejará colgado con la pregunta "por qué". No me gusta seguir ciegamente algo sin entenderlo.

EDITAR:

He intentado buscar respuestas sobre esta pregunta muchas veces antes y lo que siempre encuentro es algo como "Entonces, cuando alguien más ...". No he intentado trabajar con alguien más antes y no estoy seguro de si esa es realmente la razón por la que usa una Interfaz.

Quiero decir, porque hago todo por mi cuenta para saber qué necesita algo en mi código, ¿verdad? Y nuevamente, incluso si olvido implementar un método, veré un error que dice que un método no está definido.

EDIT 2:

La inyección de dependencia es una muy buena respuesta. Implementar interfaces en esas ayudas en caso de que necesite intercambiar implementaciones de dependencia. De alguna manera, está seguro de que se proporciona lo que necesita.

Ahora me queda un poco más claro que es un Contrato entre componentes (quizás también entre desarrolladores)

    
pregunta jen 03.04.2017 - 15:16

9 respuestas

13
  

Siempre veo respuestas que es contrato. Sí, lo entiendo.

     

Realmente puedo implementarlo e ir de acuerdo con las "normas", pero eso me dejará colgado con la pregunta "por qué".

Si estás preguntando por qué, quizás no lo entiendas.

Usar interfaces es una técnica de desacoplamiento. Permiten que una parte de su código ignore los detalles de implementación de otra parte de su código. Esto le permite cambiar aquellos detalles de la implementación con la certeza de que las otras partes de su código no se ven afectadas.

Eso reduce la carga cognitiva al hacer los cambios. Eso reduce el esfuerzo de prueba necesario para asegurarse de que las cosas funcionen correctamente después de los cambios. Y hacen las cosas mucho más fáciles cuando necesitas varias implementaciones para coexistir al mismo tiempo.

Pero a veces no necesitas esos beneficios, por lo que las interfaces solo son una sobrecarga. La mejor manera de aprender realmente este tipo de impacto es escribir código. Escribir algunos con interfaces. Escribe un poco sin. Vea cómo el diseño cambia con cada uno. Vea cómo los cambios en el programa tienen un impacto diferente según el diseño.

    
respondido por el Telastyn 03.04.2017 - 15:50
6

Si no siente que necesita una interfaz, entonces probablemente no la necesite. Solo usa la clase directamente. Mantenlo simple. Si solo una clase implementa una interfaz, es probable que sea una interfaz inútil.

Las interfaces son útiles en algunas circunstancias particulares, como

  • permitiendo múltiples implementaciones compatibles de algún servicio
  • permitiéndole simular un componente para propósitos de prueba
  • definir contratos entre subsistemas

Pero si no tienes esos requisitos, entonces no necesitas interfaces.

Los

contratos (cuando se toman interfaces) no son contratos entre desarrolladores , son contratos entre componentes . La cantidad de desarrolladores es irrelevante, la pregunta es si el sistema es lo suficientemente complejo como para que tal desacoplamiento proporcione valor.

    
respondido por el JacquesB 03.04.2017 - 17:00
2

Si, cuando escribes pruebas unitarias, utilizas un marco simulado que creó simulacros basados en la clase, no creo que necesites una interfaz para una clase muy bien definida.

La abstracción debe provenir de la refactorización

  • cuando dos clases tengan detalles de implementación comunes, es posible que desee mover esos bits en una clase abstracta, para respetar la DRY principio.
  • cuando dos clases tienen el mismo comportamiento con diferentes implementaciones, utilizaría una interfaz para definir el comportamiento e inyectar cada implementación según sea necesario

En conclusión, estoy de acuerdo con usted en que la optimización y la abstracción prematuras conducen a un exceso de ingeniería ( YAGNI ) .

En cuanto al argumento 'solo', en 2 años serás una persona diferente y agradecerás a tu yo actual si mantienes el código base mantenible. O puede que lamentes haber tomado algunas decisiones.

    
respondido por el Andrei Epure 03.04.2017 - 15:32
0

Respondiendo a este punto específico:

  

Quiero decir, porque hago todo por mi cuenta para saber qué necesita algo en mi código, ¿verdad?

El hecho de que hayas escrito algo no significa que siempre recordarás lo que necesita, especialmente algunos años después en grandes bases de código.

Es probable que le resulte más fácil navegar que alguien que no lo haya escrito, pero eso no significa que recordará todos los aspectos.

    
respondido por el Orangesandlemons 03.04.2017 - 16:54
0

Las interfaces son contratos, y el 90% del tiempo son contratos con otras personas / tecnologías. Pero también pueden ser contratos contigo mismo: tu futuro yo.

Supongamos que desea trasladar una aplicación a una nueva plataforma que requiere que cambie de dónde obtiene sus datos, pero que aún sea compatible con la plataforma anterior. Vaya, ahora tienes que escribir dos versiones diferentes de tu código de recuperación de datos y todo el código que lo usa. O simplemente use una interfaz y cargue una clase diferente para recuperar datos de una fuente diferente.

Esto es realmente un escenario del mundo real que me sucedió: tenía una aplicación WPF existente que usaba una base de datos local y se ejecutaba en tabletas (sin conexión de datos) para técnicos en el campo. Necesitaba conectarlo a UWP / iOS / Android para que funcionara en teléfonos y tabletas conectadas. Pero no podía simplemente abandonar la versión anterior y exigir que la empresa comprara cientos de nuevos teléfonos / tabletas de una sola vez. Como había abstraído la capa de acceso a datos a través de una interfaz, simplemente escribí nuevas clases de acceso a datos que contactaban con un servicio en lugar de una base de datos local, y usé DI para cargar la clase adecuada para el entorno.

    
respondido por el HiredMind 03.04.2017 - 19:23
0

En lo que a mí respecta, la escuela hace un trabajo muy pobre en la enseñanza de tales cosas. El problema es que solo entran en juego de manera significativa a medida que los sistemas se hacen más grandes.

Tomemos un caso del mundo real para mostrar el valor del resumen:

Tengo un programa aquí que, entre otras cosas, compila algunos informes en "papel" (se imprimen en un disco) y los convierte en listas de verificación de pantalla. Hay actualmente (conociendo a mi jefe, me sorprendería mucho si la lista no crece en algún momento) media docena de analizadores diferentes para diferentes estructuras de informes posibles y algunas de esas estructuras pueden tener múltiples informes.

¿Debo escribir una rutina de verificación separada para cada tipo de informe? ¡Por supuesto no! Sin embargo, no existe un "informe" estándar, el único campo que es común a cada tipo de informe es la cantidad.

Por lo tanto, tengo un tipo abstracto que representa un informe e implementa una serie de comportamientos comunes a todos los informes. Luego tengo una clase para cada tipo de informe que sabe cómo analizar su informe y proporciona los valores en respuesta a las cadenas que contienen los nombres de los campos deseados.

Del mismo modo, hay una impresora de etiquetas que toma las mismas cadenas nombradas y emite una etiqueta para pegar en el elemento.

Tanto la comprobación de la pantalla como la impresora de etiquetas funcionan completamente fuera del tipo de informe abstracto (por supuesto, se inicializó como un tipo descendiente en respuesta a la información leída de un archivo de configuración) y casi nunca se deben actualizar cuando se agregan nuevos informes al sistema.

En mi idioma principal actual, C #, las interfaces son para cuando necesitas definir un comportamiento que sea separado de la clase que lo usa. Todavía tengo que encontrar una razón para escribir una, pero considero un sistema estándar: IDisposable. Básicamente, cualquier clase que controle un recurso limitado necesita implementarlo para garantizar una limpieza adecuada.

    
respondido por el Loren Pechtel 06.04.2017 - 00:56
-1

Una de las mayores implicaciones del desacoplamiento (que es el propósito principal de las interfaces) no es solo que puedes cambiar tu código más fácilmente sin (o con menos) efectos secundarios (que ya son enormes).

(Esta es no una descripción exhaustiva de los beneficios de las interfaces)

También puede escribir su código de manera más flexible, lo que resulta en menos código (menos declaraciones IF, etc.). Esto es especialmente cierto si maneja muchos objetos de diferentes clases, tal vez incluso en un contenedor / matriz.

Imagina el siguiente escenario: Tu programa tiene clases para Gato, Perro, Coche, Tren, Viento. Desea tener una matriz o una lista de los objetos de estas clases ordenados por su velocidad de movimiento. Ahora, estas clases PODRÍAN derivar de la misma clase (s) base, porque todas tienen una propiedad de "velocidad". La clase base podría ser "MoveableObject". Pero también podrían tener algo más en común, por ejemplo, la capacidad de crear una cadena de registro (Método: CreateLogString ()). Como todas estas clases tendrían esta capacidad, necesitaría crear un método virtual "CreateLogString" en la clase hbase "MoveableObject". Por otro lado, esto obliga a todos los objetos móviles a implementar CreateLogString y viceversa.

Para declarar "habilidades" para las clases (como la capacidad de crear una cadena de registro o la de tener velocidad), puedes implementar 2 interfaces: ILogstringAble, IHasSpeed (o como quieras llamarlas).

Ahora, si implementa un método que toma un objeto y registra su valor actual, puede codificar ese método para recibir un argumento de tipo ILogstringAble. No es necesario que sobrecargue este método para todas estas clases.

void PrintLogs(ILogstringAble obj) {
    string s = obj.CreateLogString();
    ...do something...
    print(s);
}

Si tiene una matriz de objetos IHasSpeed, puede ordenar esa matriz usando la propiedad speed de IHasSpeed. Esta tarea no sería tan fácil si no abstraes la capacidad de tener velocidad mediante el uso de esa interfaz.

En resumen: con las interfaces puede subir una capa de abstracción y "categorizar" objetos según su comportamiento común, incluso si son instancias de diferentes clases.

    
respondido por el Stefan Woe 03.04.2017 - 16:42
-1

Encuentro que trabajar con abstracción e interfaces en las fases de diseño y arquitectura me ayuda a pensar más en qué estoy tratando de lograr en lugar de cómo . El resultado es un diseño que es relativamente independiente del lenguaje y la plataforma y que puede extenderse fácilmente a problemas similares que veré en el futuro.

    
respondido por el PerryD 03.04.2017 - 18:02
-3

Una interfaz en idiomas como C #, no es un contrato. Es simplemente una colección de métodos, propiedades y firmas de eventos. Para ser un contrato, cada uno de esos miembros necesitaría una especificación (es decir, condiciones previas, condiciones posteriores), así como invariantes para la abstracción en su totalidad. Dado que C # y otros idiomas .net carecen de formas formales de especificar contratos (excepto las herramientas no terminadas proporcionadas por Microsoft), solo podemos crear contratos informales en dicho idioma.

En .net o Java, la única razón para usar una interfaz es porque se ve obligado a hacerlo, debido a algunos requisitos de la herramienta, o porque está obligado a hacerlo porque necesita herencia múltiple, y no hay otra manera de hacerlo. Las interfaces innecesarias simplemente saturan el código y causan errores humanos adicionales.

Si siente la necesidad de agregar interfaces superfluas debido a la presión de sus colegas, considere lo siguiente:

  • Muchos lenguajes de programación orientados a objetos no tienen el concepto de una interfaz, porque admiten la herencia múltiple usando clases. Los posibles problemas con la herencia múltiple se resolvieron en lenguajes de programación mucho antes de que se diseñaran Java y .net. El concepto de una interfaz, que es abstractamente idéntico a una clase vacía, se puede ver como una solución para una falla en un lenguaje de programación: no es un buen soporte para la herencia múltiple.
  • Algunas personas afirman que las interfaces proporcionan "desacoplamiento". El código que utiliza una interfaz está fuertemente acoplado a esa interfaz, y una clase que implementa una interfaz también está fuertemente acoplada a esa interfaz. Por lo tanto, una interfaz no es más "desacoplamiento" que una clase base en la misma situación.
  • Las interfaces no son contratos (ver arriba).
  • El uso excesivo de interfaces puede promover la herencia sobre la composición, cuando la composición es preferible. Una clase puede implementar muchas interfaces diferentes, pero solo puede heredar de una clase base. Esto puede llevar a clases hinchadas. Un diseño alternativo, utilizando clases base en lugar de interfaces, y promoviendo la composición, tendría esa misma clase con instancias de otras clases, cada una de las cuales hereda de una clase base diferente.
  • Al crear una biblioteca reutilizable para otros, al proporcionar una interfaz en lugar de una clase base, permite que los usuarios de su biblioteca implementen esa interfaz por cualquier clase, evitando restricciones de herencia. Esto puede ser necesario y algo bueno. Por otro lado, al proporcionar solo clases base en lugar de interfaces, puede promover la composición sobre la herencia.
respondido por el Frank Hileman 04.04.2017 - 01:50

Lea otras preguntas en las etiquetas