2012-01-19 11 views
25

He trabajado/visto algunos proyectos de aplicaciones web de hibernación de primavera que tienen tantas interfaces como clases de dao y servicio real.¿Por qué siempre tener interfaces de implementación únicas en las capas de servicio y dao?

siempre pensé que estos dos como las principales razones para tener estas interfaces de aplicación individuales:

  1. primavera puede cablear implementación real como dependencias en una clase dada (acoplamiento débil)

    public class Person { 
        @Autowired 
        private Address address; 
    
        @Autowired 
        private AccountDetail accountDetail; 
    
        public Person(Address address, AccountDetail accountDetail) 
        { // constructor 
    
  2. Mientras estoy probando la unidad, puedo crear clases simuladas y probar una clase aisladamente.

    Address mockedAddress = mock(Address); 
    AccountDetail mockedAccountDetail = mock(AccountDetail); 
    Person underTestPerson = new Person(mockedAddress, mockedAccountDetail); 
    // unit test follows 
    

embargo, en los últimos tiempos, me di cuenta de que:

primavera puede cablear las clases concretas de aplicación como dependencias:

public class Person { 

@Autowired 
private AddressImpl address; 

@Autowired 
private AccountDetailImpl accountDetail; 

public Person(AddressImpl address, AccountDetailImpl accountDetail) { 
// constructor 

marcos Mock como EasyMock pueden burlarse de clases concretas, así

AddressImpl mockedAddress = mock(AddressImpl); 
AccountDetailImpl mockedAccountDetail = mock(AccountDetailImpl); 
Person underTestPerson = new Person(mockedAddress, mockedAccountDetail); 
// unit test follows 

Además, según la discusión this, creo que el resumen es que, en una sola aplicación, las interfaces se usan en exceso, probablemente fuera de la convención o el hábito. Por lo general, tienen más sentido en los casos en que interactuamos con otra aplicación, por ejemplo, slf4j, utilizada por muchas aplicaciones en todo el mundo. Dentro de una sola aplicación, una clase es casi una abstracción como lo es una interfaz.

Por lo tanto, mi pregunta es por qué todavía necesitamos interfaces y luego tenemos implementaciones únicas como * clases ServiceImpl y * DaoImpl e innecesariamente aumentamos el tamaño de nuestra base de códigos. ¿Hay algún problema en burlarse de las clases concretas que no conozco?

Cada vez que hablo de esto con mis compañeros, la única respuesta que recibo es que el servicio de implementación y las clases dao basadas en interfaces es EL DISEÑO que todos siguen: mencionan las mejores prácticas de primavera, OOP, DDD, etc. todavía no se obtiene una razón pragmática detrás de tener tantas interfaces dentro de una aplicación aislada.

+2

En cuanto a las respuestas que obtuvo, no veo cómo se puede invocar a DDD como una razón para lanzar una interfaz en frente de cada objeto. DDD no tiene nada que ver con eso. Incluso OOP es una mala justificación. Si toma elementos como L, I y D de SOLID, solo especifican cómo debe diseñar abstracciones, como interfaces y para qué debe usarlas, y no * las debe usar todo el tiempo *. Así que como dijiste, creo que todo se reduce a lo de "mejores prácticas de primavera" o simplemente a las personas que lo hacen por hábito. – guillaume31

Respuesta

14

Hay más ventajas para las interfaces, como en el proxying. Si su clase implementa una interfaz, los proxys dinámicos JDK se usarán por defecto para AOP. Si usa las implementaciones directamente, se verá forzado a usar proxies CGLIB haciendo proxy-target-class = true. Estos requieren la manipulación del código de bytes a diferencia de los proxies JDK.

lea here para más información sobre esto.

Lea otra discusión en what reasons are there to use interfaces (Java EE or Spring and JPA) para más información.

14

Es un tema muy controvertido. En resumen, no hay ninguno, al menos para ti, el desarrollador.

En el mundo EJB2, las interfaces Home y Remote eran obligatorias, y fueron exactamente por una razón @AravindA menciona: proxies. La seguridad, la comunicación remota, la puesta en común, etc., todo podría estar envuelto en un proxy, y proporcionar los servicios solicitados estrictamente dentro de la biblioteca estándar (como en el DynamicProxy).

Ahora que tenemos javaassist y cglib, Spring (Hibernate, EJB3 si lo prefiere) son perfectamente capaces de instrumentar sus clases como desarrolladores de frameworks. El problema es que lo que hacen es algo muy molesto: generalmente te piden que agregues un constructor sin parámetros. -Espera, ¿tenía aquí los parámetros? -Nevermind, solo agrega el constructor.

Por lo tanto, las interfaces están aquí para mantener su cordura. Aún así, es extraño, un constructor sin argumentos para una clase con el constructor adecuado no es algo que tenga sentido para mí, ¿verdad? Resulta que (debería haber leído las especificaciones, lo sé) que Spring crea un equivalente funcional de una interfaz fuera de su clase: una instancia sin estado (o ignorado) y todos los métodos anulados. Por lo tanto, tiene una instancia "real" y una "interfaz falsa", y lo que hace la interfaz falsa es que sirve toda la magia de seguridad/transacción/interacción para usted. Agradable, pero difícil de entender, y parece un error si no lo has desarmado.

Además, si implementa una interfaz en su clase, (al menos algunas versiones de) Spring decide repentinamente que va a utilizar solo esta interfaz y la aplicación simplemente no funciona sin ningún motivo aparente.

Por lo tanto, hasta ahora el motivo es la seguridad y la cordura. Hay razones por las que es una buena práctica, pero por su publicación, veo que ya las leyó todas. La razón más importante que puedo ver hoy es la métrica de WTH/minuto, especialmente si estamos hablando de recién llegados a su proyecto.

Cuestiones relacionadas