2009-07-13 14 views
12

Decir que tengo una clase que tiene el siguiente aspecto:Principio de Responsabilidad Individual: ¿todos los métodos públicos en una clase tienen que usar todas las dependencias de clase?

internal class SomeClass 
{ 
    IDependency _someDependency; 

    ... 


    internal string SomeFunctionality_MakesUseofIDependency() 
    { 
    ... 
    } 
} 

Y luego quiero añadir funcionalidad que se relacionan pero hace uso de una dependencia diferente para lograr su propósito. Tal vez algo como lo siguiente:

internal class SomeClass 
{ 
    IDependency _someDependency; 

    IDependency2 _someDependency2; 

    ... 


    internal string SomeFunctionality_MakesUseofIDependency() 
    { 
    ... 
    } 

    internal string OtherFunctionality_MakesUseOfIDependency2() 
    { 
    ... 
    } 
} 

Cuando escribo pruebas unitarias para esta nueva funcionalidad (o actualizar la unidad de pruebas que tengo para la funcionalidad existente), me encuentro la creación de una nueva instancia de SomeClass (SUT) al pasar nulo por la dependencia que no necesito para el determinado tipo de funcionalidad que estoy buscando probar.

Esto me parece un mal olor, pero la razón por la que me encuentro en este camino es porque me encontré creando nuevas clases para cada nueva funcionalidad que estaba presentando. Esto también parecía algo malo, así que comencé a intentar agrupar una funcionalidad similar.

Mi pregunta: ¿deberían consumirse todas las dependencias de una clase por toda su funcionalidad, es decir, si diferentes bits de funcionalidad usan dependencias diferentes, es una pista de que probablemente deberían vivir en clases separadas?

Respuesta

3

¿El SomeClass mantener un estado interno, o es sólo "Montaje" varias piezas de funcionalidad? Se puede volver a escribir de esa manera:

internal class SomeClass 
{ 
    ... 


    internal string SomeFunctionality(IDependency _someDependency) 
    { 
    ... 
    } 

    internal string OtherFunctionality(IDependency2 _someDependency2) 
    { 
    ... 
    } 
} 

En este caso, no se puede romper si SRP SomeFunctionality y OtherFunctionality son de alguna manera (funcionalmente) relacionada que no es evidente el uso de marcadores de posición.

Y tiene el valor agregado de poder seleccionar la dependencia a usar del cliente, no en la hora de creación/DI. Tal vez algunas pruebas que definan casos de uso para esos métodos ayuden a aclarar la situación: si puede escribir un caso de prueba significativo en el que se invoquen ambos métodos en el mismo objeto, entonces no se rompe el SRP.

En cuanto al patrón Fachada, lo he visto demasiadas veces alocado como para gustarle, ya sabe, cuando termina con una clase de más de 50 métodos ... La pregunta es: ¿por qué la necesita? Por razones de eficiencia à la old-timer EJB?

+0

Esto resuelve mi problema ya que las dependencias no tienen noción de estado, sino que estaban encapsulando la funcionalidad (debería haber mencionado esto en mi pregunta - pero no lo consideró en ese momento) – jpoh

0

Por lo general, agrupo los métodos en clases si usan un estado compartido que se puede encapsular en la clase. Tener dependencias que no son utilizadas por todos los métodos en una clase puede ser un olor a código pero no muy fuerte. Normalmente, solo separe los métodos de las clases cuando la clase sea demasiado grande, la clase tenga demasiadas dependencias o los métodos no tengan estado compartido.

0

Mi pregunta: ¿deberían consumirse todas las dependencias de una clase por todas sus funcionalidades, es decir, si diferentes bits de funcionalidad usan dependencias diferentes, es una pista de que probablemente deberían vivir en clases separadas?

Está una pista, lo que indica que su clase puede ser un poco incoherente ("haciendo algo más que una cosa"), pero como usted dice, si se toma esto demasiado lejos, usted termina con una nueva clase por cada pieza de nueva funcionalidad. Por lo tanto, desearía introducir objetos de fachada para unirlos de nuevo (parece que un objeto de fachada es exactamente lo opuesto a esta regla de diseño particular).

Tienes que encontrar un buen equilibrio que funcione para ti (y para el resto de tu equipo).

+0

Me interesaría escuchar si alguien piensa que la fachada es lo contrario de esta regla – Calanus

0

Me parece una sobrecarga. Está tratando de hacer algo y hay dos formas de hacerlo, de una forma u otra. En el nivel SomeClass, tengo una dependencia para hacer el trabajo, luego tengo esa única clase dependiente que admite las dos (o más) formas de hacer lo mismo, muy probablemente con parámetros de entrada mutuamente excluyentes. En otras palabras, tendría el mismo código que tiene para SomeClass, pero defínalo como SomeWork y no incluya ningún otro código no relacionado.

HTH

0

Una fachada se utiliza cuando desea ocultar la complejidad (como una interfaz a un sistema heredado) o si desea consolidar la funcionalidad al mismo tiempo que es compatible con versiones anteriores desde la perspectiva de la interfaz.

La clave en su caso es por qué tiene los dos métodos diferentes en la misma clase. Es la intención de tener una clase que agrupe tipos similares de comportamiento incluso si se implementa a través de un código no relacionado, como en la agregación. O bien, ¿está intentando admitir el mismo comportamiento pero tiene implementaciones alternativas según los detalles, lo que sería una pista para una solución de tipo heredado/sobrecargado?

El problema será si esta clase seguirá creciendo y en qué dirección. Dos métodos no harán la diferencia, pero si esto se repite con más de 3, deberá decidir si desea declararlo como fachada/adaptador o si necesita crear clases secundarias para las variaciones.

Sus sospechas son correctas, pero el olor es solo el humo de una brasa ardiente. Debe vigilarlo en caso de que se encienda y luego tenga que tomar una decisión sobre cómo apagar el fuego antes de que se descontrole.

11

Cuando cada método de instancia toca cada variable de instancia, la clase es cohesiva máxima. Cuando ningún método de instancia comparte una variable de instancia con ninguna otra, la clase es mínimamente cohesiva. Si bien es cierto que nos gusta que la cohesión sea alta, también es cierto que se aplica la regla 80-20. Obtener ese último pequeño aumento en la cohesión puede requerir un gran esfuerzo.

En general, si tiene métodos que no usan algunas variables, es un olor. Pero un pequeño olor no es suficiente para refactorizar completamente la clase. Es algo de lo que hay que preocuparse y estar pendiente, pero no recomiendo una acción inmediata.

Cuestiones relacionadas