unica solid software responsabilidad principios principio patrones para inversión ejemplos ejemplo dummies diseño dependencias design oop srp solid-principles

design - solid - ¿Cómo se determina qué tan grosera o fina debe ser una ''responsabilidad'' cuando se utiliza el principio de responsabilidad única?



solid java (6)

@Derick Bailey: buena explicación
Algunas adiciones:
Es totalmente aceptable que la aplicación de SRP sea una base contextual.
La pregunta aún permanece: ¿hay alguna manera objetiva de definir si una clase dada viola a SRP?

Algunos contextos de diseño son bastante obvios (como el ejemplo del coche de Derick), pero por lo demás los contextos en los que el comportamiento de una clase debe definirse permanecen borrosos muchas veces.

Para tales casos, podría ser útil si el comportamiento de clase difusa se analiza dividiendo sus responsabilidades en diferentes clases y luego midiendo el impacto de las nuevas relaciones estructurales y de comportamiento que han emanado debido a la división.

Tan pronto como se complete la división, las razones para mantener las responsabilidades divididas o fusionarlas en una única responsabilidad se hacen evidentes de inmediato.

He aplicado este enfoque y que me ha dado buenos resultados.

Pero mi búsqueda para buscar "formas objetivas de definir una responsabilidad de clase" aún continúa.

En el SRP, una ''responsabilidad'' se describe generalmente como ''una razón para cambiar'', de modo que cada clase (¿u objeto?) Debería tener una sola razón por la que alguien debería entrar allí y cambiarla.

Pero si lleva esto al extremo de grano fino, podría decir que un objeto que suma dos números es una responsabilidad y una posible razón para cambiar. Por lo tanto, el objeto no debe contener otra lógica, ya que produciría otra razón para el cambio.

Tengo curiosidad por saber si hay alguien por ahí que tenga alguna estrategia de ''alcance'', el principio de responsabilidad única que es un poco menos objetivo.


No veo la realización de una tarea como agregar dos números juntos como una responsabilidad. Las responsabilidades vienen en diferentes formas y tamaños, pero ciertamente deben verse como algo más grande que realizar una sola función.

Para comprender mejor esto, probablemente sea útil diferenciar claramente entre lo que una clase es responsable y lo que hace un método. Un método debe "hacer solo una cosa" (por ejemplo, agregar dos números, aunque para la mayoría de los propósitos ''+'' es un método que ya lo hace), mientras que una clase debe presentar una única y clara "responsabilidad" para sus consumidores. Su responsabilidad está en un nivel mucho más alto que un método.

Una clase como Repository tiene una responsabilidad clara y singular. Tiene múltiples métodos como Guardar y Cargar, pero una clara responsabilidad de proporcionar soporte de persistencia para las entidades Persona. Una clase también puede coordinar y / o resumir las responsabilidades de las clases dependientes, nuevamente presentando esto como una responsabilidad única para otras clases consumidoras.

La conclusión es que si la aplicación de SRP conduce a clases de método único cuyo propósito general parece ser solo ajustar la funcionalidad de ese método en una clase, entonces SRP no se está aplicando correctamente.


Respetuoso no estoy de acuerdo cuando lo anterior de Chris Nicola dice que "una clase debería presentar una única y clara" responsabilidad "para con sus consumidores

Creo que SRP se trata de tener un buen diseño dentro de la clase, no clientes de la clase.

Para mí, no está muy claro cuál es la responsabilidad, y la prueba es la cantidad de preguntas que plantea este concepto.

"única razón para cambiar"

o

"si la descripción contiene la palabra" y ", entonces debe dividirse"

lleva a la pregunta: ¿dónde está el límite? Al final, cualquier clase con 2 métodos públicos tiene 2 razones para cambiar, ¿no es así?

Para mí, el verdadero SRP conduce al patrón Fachada, donde tienes una clase que simplemente delegades las llamadas a otras clases

Por ejemplo:

class Modem send() receive() Refactors to ==> class ModemSender class ModelReceiver + class Modem send() -> ModemSender.send() receive() -> ModemReceiver.receive()

Las opiniones son bienvenidas


Tiendo a pensar en términos de "velocidad de cambio" de los requisitos del negocio en lugar de "razón para cambiar".

La pregunta es, de hecho, cómo las cosas cambiarán juntas , no si podrían cambiar o no.

La diferencia es sutil, pero me ayuda. Consideremos el ejemplo en wikipedia sobre el motor de informes:

  • si la probabilidad de que el contenido y la plantilla del informe cambien al mismo tiempo es alta, puede ser un componente porque aparentemente están relacionados. (También puede ser dos)

  • pero si la probabilidad de que el contenido cambie sin la plantilla es importante, entonces debe ser de dos componentes, porque no están relacionados. (Sería peligroso tener uno)

Pero sé que es una interpretación personal del SRP.

Además, una segunda técnica que me gusta es: "Describe tu clase en una oración". Usualmente me ayuda a identificar si hay una responsabilidad clara o no.


Una regla empírica simple que uso es que: el nivel o la granularidad de la responsabilidad debe coincidir con el nivel o la granularidad de la "entidad" en cuestión. Obviamente, el propósito de un método siempre será más preciso que el de una clase, servicio o componente.

Una buena estrategia para evaluar el nivel de responsabilidad puede ser usar una metáfora apropiada. Si puede relacionar lo que está haciendo con algo que existe en el mundo real, puede ayudarlo a obtener otra visión del problema que está tratando de resolver, incluida la capacidad de identificar los niveles apropiados de abstracción y responsabilidad.


todo se reduce al contexto de lo que estás modelando. He escrito extensamente y presentado los principios SOLID y abordo específicamente su pregunta en mis discusiones sobre responsabilidad única.

La siguiente apareció por primera vez en la edición de enero / febrero de 2010 de Code Magazine, y está disponible en línea en "SOLID Software Development, One Step at a Time".

El Principio de Responsabilidad Individual dice que una clase debe tener una, y solo una, razón para cambiar.

Esto puede parecer contraintuitivo al principio. ¿No sería más fácil decir que una clase solo debería tener una razón para existir? En realidad, ninguna razón para existir podría ser llevada fácilmente al extremo que causaría más daño que bien. Si lo llevas a ese extremo y construyes clases que tienen una razón para existir, puedes terminar con solo un método por clase. Esto provocaría una gran expansión de las clases, incluso para los procesos más simples, haciendo que el sistema sea difícil de entender y difícil de cambiar.

La razón por la cual una clase debe tener una razón para cambiar, en lugar de una razón para existir, es el contexto comercial en el que está construyendo el sistema. Incluso si dos conceptos son lógicamente diferentes, el contexto comercial en el que se necesitan puede hacer que se vuelvan uno y el mismo. El punto clave para decidir cuándo debe cambiar una clase no se basa en una separación puramente lógica de conceptos, sino en la percepción del concepto por parte del negocio. Cuando la percepción y el contexto del negocio ha cambiado, entonces tienes una razón para cambiar la clase. Para comprender qué responsabilidades debe tener una clase única, primero debe comprender qué concepto debe ser encapsulado por esa clase y dónde espera que cambien los detalles de implementación de ese concepto.

Considere un motor en un automóvil, por ejemplo. ¿Te importa el funcionamiento interno del motor? ¿Le importa que tenga un tamaño específico de pistón, árbol de levas, inyector de combustible, etc.? ¿O solo le importa que el motor funcione como se espera cuando ingrese al automóvil? La respuesta, por supuesto, depende completamente del contexto en el que necesite usar el motor.

Si eres un mecánico que trabaja en una tienda de automóviles, probablemente te preocupes por el funcionamiento interno del motor. Debe conocer el modelo específico, los distintos tamaños de piezas y otras especificaciones del motor. Si no tiene esta información disponible, es probable que no pueda realizar el mantenimiento adecuado del motor. Sin embargo, si usted es una persona común y corriente que solo necesita transporte del punto A al punto B, es probable que no necesite ese nivel de información. La noción de pistones individuales, bujías, poleas, correas, etc., es casi insignificante para usted. Solo le importa que el automóvil que conduce tenga un motor y funcione correctamente.

El ejemplo del motor conduce directamente al corazón del Principio de Responsabilidad Individual. Los contextos de conducir el automóvil versus dar servicio al motor proporcionan dos nociones diferentes de lo que debe y no debe ser un concepto único: una razón para el cambio. En el contexto del servicio del motor, cada pieza individual debe estar separada. Debe codificarlos como clases individuales y asegurarse de que cumplan con sus especificaciones individuales. En el contexto de conducir un automóvil, sin embargo, el motor es un concepto único que no necesita ser desglosado más. Es probable que tenga una sola clase llamada Engine, en este caso. En cualquier caso, el contexto ha determinado cuál es la separación apropiada de responsabilidades.