¿Cuál es el punto de que cada clase de servicio tenga una interfaz? [duplicar]

84

En la empresa en la que trabajo, cada clase de servicio tiene una interfaz correspondiente. ¿Es esto necesariamente? La mayoría de estas interfaces solo las utiliza una sola clase y no estamos creando ningún tipo de API pública. Con las bibliotecas modernas de burla capaces de simular clases concretas e IDEs capaces de extraer una interfaz de una clase con dos o más clics, ¿esto es solo un remanente de tiempos anteriores?

    
pregunta Bob Roberts 24.05.2012 - 17:53

6 respuestas

79

Su compañía está siguiendo los principios de SOLID y está apuntando a una interfaz en lugar de a una clase concreta que no agrega gastos generales al programa. Lo que están haciendo es una cantidad muy moderada de trabajo extra que puede devolver volúmenes cuando las suposiciones que usted está haciendo terminan siendo falsas ... y nunca se puede decir cuál será la suposición. Lo que está recomendando, aunque es un poco menos de trabajo, puede costar muchas, muchas, muchas horas de refactorización que podrían haberse realizado antes de tiempo simplemente siguiendo los principios básicos de diseño de OO.

Deberías aprender de estos chicos y considerarte afortunado. Ojalá hubiera trabajado en un entorno donde el diseño sólido fuera un objetivo prioritario.

    
respondido por el Crazy Eddie 24.05.2012 - 17:59
66

Dada su pregunta, asumo que las razones de este tipo de diseño no están documentadas.

El uso no justificado de una interfaz con una implementación única es totalmente incorrecto, ya que esto infringe YAGNI . En mi experiencia, esto también ha sido bastante perjudicial en cuanto a mantenimiento, principalmente porque los métodos que implementan la interfaz se ven forzados a ser innecesariamente públicos. Después de reunir más experiencia de refactorización , probablemente aprenderás a apreciar el encanto modesto de private y package private modificadores de acceso que le permiten a uno centrar la atención en una sola clase / paquete.

En cuanto al uso justificado por indocumentado de este lenguaje, a mi modo de ver es tan malo, en primer lugar porque no permite a un mantenedor "decir lo bueno de lo malo". Como resultado, esto deja a uno entre opciones no bastante atractivas. Las opciones son, ya sea que mantengas el material público cuestionable tal como está, por lo tanto, repetidamente disminuyendo la productividad cada vez que necesites cambiar el código, o realizas cambios riesgosos al "ceder" la implementación única de forma ciega. mantener POJO - exponiéndonos al riesgo de descubrir dolorosamente que esta es una manera incorrecta, eso algún otro (módulo de remoto ) fuera de su vista espera la interfaz.

He pasado por "revelaciones" causadas por el colapso erróneo de la interfaz de implementación única varias veces. Cada vez ha sido una experiencia bastante educativa, pero realmente no me gustaría volver allí. Lo que sucede es que esto sucede en las últimas pruebas, en la integración o incluso en la aceptación por parte del usuario y revertir / corregir el error cometido hace mucho tiempo en esta etapa es bastante engorroso.

  • Una opción que no debe dejarse sin mencionar es investigar si el uso no documentado está justificado (y, después de eso, colapsar o documentar respectivamente) justo en el momento en que lo encuentre.

    Para mí, este ha sido bastante contraproducente. Este enfoque esencialmente lo obliga a realizar pruebas de integración completas, que probablemente sea una de las formas más eficientes de interrumpir un flujo en medio de algunas correcciones / refactorizaciones complicadas.

  

Simplemente no pude ver la practicidad ... las interfaces se usan una a una como com.company.service.foo y com.company.service.foo.impl

A continuación se trata de cómo normalmente manejo casos como ese.

  1. Cree un ticket en el seguimiento de problemas , como " PRJ-123 Undocumented uso cuestionable de la interfaz con implementación única en Foo / FooImpl ".
    Agregue a la descripción del ticket o comente una explicación de que esto daña la capacidad de mantenimiento y señale que sin la documentación, esto se parece a overengineering . Agregue un comentario que sugiera solucionar el problema "colapsándolo" en un POJO, para facilitar el mantenimiento.
  2. Espere un momento, por si acaso, si alguien viene a explicar las cosas. Esperaría una o dos semanas al menos

    • Si alguien explica el propósito, a) ponga eso en el ticket, b) agregue a Foo javadocs algo como propósito de interfaz explicado en el ticket PRJ-123 , c) cierre el ticket, d) Salta los siguientes tres pasos.
    • De lo contrario, ...
  3. Acérquese al jefe del equipo o al gerente para preguntar qué pensarían si yo arreglara el ticket según lo sugerido. .
  4. Colapsar a POJO según la solución sugerida, organizar revisión de código si es posible (en casos resbaladizos como ese, no te hará daño cubrir tu espalda).
  5. Espere hasta que el cambio pase la prueba completa y actualice el ticket dependiendo de su resultado: agregue la información sobre si el cambio pasó la prueba o no.
  6. Cree y administre un nuevo ticket de seguimiento de problemas para tratar los casos similares restantes según el resultado de su ticket piloto ( PRJ-123 ): documente el propósito o colapse a POJO.

    
respondido por el gnat 24.05.2012 - 23:18
31

Aquí es cómo Adam Bien piensa acerca de esta pregunta: Service s = new ServiceImpl () - ¿Por qué lo está haciendo?

  

Eso no solo es una exageración (y lo opuesto a la idea de "Convención sobre la configuración"), sino que causa un daño real:

     
  1. Imagina que obtienes otra implementación (que es todo el punto de una interfaz): ¿cómo la llamarías?
  2.   
  3. Duplica la cantidad de artefactos y aumenta significativamente la "complejidad"
  4.   
  5. Es realmente divertido leer los javadocs en la interfaz y el impl - otra redundancia
  6.   
  7. La navegación en el IDE es menos fluida
  8.   

y estoy de acuerdo con él.

Tal vez sus compañeros de trabajo todavía estén atascados a tiempo con J2EE, porque esto era necesario cuando se trabaja con J2EE, tal vez pueda encontrar en Internet antiguos tutoriales sobre tiempos difíciles en J2EE.

    
respondido por el Xoke 03.09.2012 - 19:08
17

Las interfaces de Java no se tratan solo de simulacros (aunque, por supuesto, eso es un factor). Una interfaz expone un contrato público para su servicio, sin detalles de implementación como métodos o atributos privados.

Tenga en cuenta que "público" cuando utiliza servicios internos (como en su caso) se refiere a los usuarios reales de dichos servicios, incluidos, entre otros, a otros programadores y servicios internos.

    
respondido por el Andres F. 24.05.2012 - 18:11
10

Una posible razón para que cada clase de servicio tenga una interfaz es que hace que las interacciones con marcos sofisticados (por ejemplo, Spring, JEE) sean mucho más simples. Esto se debe a que Java puede simplemente generar objetos de interceptor contra interfaces (ver java.lang.reflect.Proxy ); hacerlo contra clases concretas es mucho más complicado y contiene algunas advertencias no obvias cuando se trabaja con múltiples cargadores de clases diferentes. Esto es doblemente cierto si trabaja con OSGi, donde esas interfaces de servicio terminarán siendo cargadas desde un cargador de clases diferente de las implementaciones de esos servicios. Eso (junto con el tejido de descubrimiento de servicios) a su vez impone una separación muy fuerte entre cada servicio y sus clientes; los clientes literalmente no pueden romper la abstracción.

Tenga en cuenta que incluso si un IDE puede extraer una interfaz de una clase con un solo clic, no significa que necesariamente vaya a extraer la interfaz correcta . Todavía se necesita inteligencia.

    
respondido por el Donal Fellows 26.05.2012 - 16:39
0

Parece una sobrecarga utilizar la Interfaz inicialmente ... pero más adelante, cuando necesitamos extender alguna funcionalidad, estas Interfaces ayudan mucho.

Si solo hace una implementación concreta, tiene que cambiar mucho la implementación del código. Pero al usar la interfaz, solo necesita agregar una nueva clase que implemente el contrato de Interfaz (y puede llamar a un nuevo objeto de clase desde la variable de referencia de Interfaz antigua).

    
respondido por el kundan bora 26.05.2012 - 11:28

Lea otras preguntas en las etiquetas