El Principio de responsabilidad única se trata de que su código solo haga 1 cosa y puede dividir toda la funcionalidad en varias clases, todas ellas destinadas a hacer 1 cosa específica. Un ejemplo es una clase específica para validación, hacer algo de lógica de negocios, enriquecer un modelo, recuperar datos, actualizar datos, navegación, etc.
La separación de inquietudes se trata de que su código no esté estrechamente vinculado a otras clases / sistemas. El uso de interfaces en su código ayuda mucho, de esta manera puede acoplar libremente clases / sistemas a su código. Una ventaja de esto es que también es más fácil hacer una prueba unitaria de su código. Hay muchos marcos de trabajo (IoC) que pueden ayudarlo a lograr esto, pero puede implementarlo usted mismo, por supuesto.
Un ejemplo de algo SoC, pero no tener SRP
public class Foo
{
private readonly IValidator _validator;
private readonly IDataRetriever _dataRetriever;
public Foo(IValidator validator, IDataRetriever dataRetriever)
{
_validator = validator;
_dataRetriever = dataRetriever;
}
public NavigationObject GetDataAndNavigateSomewhereIfValid()
{
var data = _dataRetriever.GetAllData();
if(_validator.IsAllDataValid(data))
{
object b = null;
foreach (var item in data.Items)
{
b = DoSomeFancyCalculations(item);
}
if(_validator.IsBusinessDataValid(b))
{
return ValidBusinessLogic();
}
}
return InvalidItems();
}
private object DoSomeFancyCalculations(object item)
{
return new object();
}
private NavigationObject ValidBusinessLogic()
{
return new NavigationObject();
}
private NavigationObject InvalidItems()
{
return new NavigationObject();
}
}
Como puede ver, este código no está estrechamente acoplado a clases u otros sistemas, porque solo usa algunas interfaces para hacer cosas. Esto es bueno desde el punto de vista del SoC.
Como puede ver, esta clase también contiene 3 métodos privados que hacen algunas cosas elegantes. Desde el punto de vista de SRP, esos métodos probablemente deberían ubicarse dentro de algunas clases propias. 2 de ellos hacen algo con la navegación, que encajaría en alguna clase de INavigation. El otro hace algunos cálculos sofisticados sobre un elemento, esto probablemente podría ubicarse dentro de una clase IBusinessLogic.
Al tener algo como esto, ambos tienen SoC y SRP en su lugar:
public class Foo
{
private readonly IValidator _validator;
private readonly IDataRetriever _dataRetriever;
private readonly IBusinessLogic _businessLogic;
private readonly INavigation _navigation;
public Foo(IValidator validator, IDataRetriever dataRetriever, IBusinessLogic businessLogic, INavigation navigation)
{
_validator = validator;
_dataRetriever = dataRetriever;
_businessLogic = businessLogic;
_navigation = navigation;
}
public NavigationObject GetDataAndNavigateSomewhereIfValid()
{
var data = _dataRetriever.GetAllData();
if(_validator.IsAllDataValid(data))
{
object b = null;
foreach (var item in data.Items)
{
b = _businessLogic.DoSomeFancyCalculations(item);
}
if(_validator.IsBusinessDataValid(b))
{
return _navigation.ValidBusinessLogic();
}
}
return _navigation.InvalidItems();
}
}
Por supuesto, podría debatir si toda esta lógica debería colocarse en el GetDataAndNavigateSomewhereIfValid
método. Esto es algo que debes decidir por ti mismo. Para mí, parece que este método está haciendo demasiadas cosas.
En cuanto a que el SRP solo se aplica a nivel de clase, en sus libros Robert C. Martin (hasta donde sé, él popularizó si no se le ocurrió el concepto) afirma:
Código limpio, página. 138 : "El Principio de Responsabilidad Única (SRP) establece que una clase o módulo debe tener una, y solo una, razón para cambiar".
En Principios, patrones y prácticas ágiles en C #, página 116 : "[...] y relaciona la cohesión con las fuerzas que hacen que un módulo , o una clase, cambie".
El énfasis es mío.
En APPP , habla con mayor extensión sobre SRP y se centró casi por completo en el nivel de clase. Si bien parece centrarse en el nivel de clase, creo que el principio también se dirige a los módulos y otras construcciones de nivel superior.
Por tal razón, no calificaría a SRP como SoC a nivel de clase como sugiere en su pregunta.
fuente
Aquí puede encontrar un video corto que explica claramente la diferencia entre esas terminologías. https://www.youtube.com/watch?v=C7hkrV1oaSY
Separación de preocupaciones (SoC). Divida su aplicación en distintas funciones con la menor superposición de funcionalidad posible. (Microsoft)
“Preocupación” = “característica distinta” = “sección distinta”
La "preocupación" funciona tanto en niveles altos como bajos
El principio de responsabilidad única establece que cada módulo o clase debe tener responsabilidad sobre una sola parte de la funcionalidad proporcionada por el software, y esa responsabilidad debe estar completamente encapsulada por la clase. Todos sus servicios deben estar estrechamente alineados con esa responsabilidad. (Definición de Wikipedia)
"Responsabilidad" = "razón para cambiar"
cambiar que? “Una sola parte de la funcionalidad proporcionada por el software” = Unidad básica
Conclusión
El Principio de Responsabilidad Única funciona en unidades básicas -> trabaja en niveles bajos
La separación de preocupaciones funciona tanto en niveles altos como bajos
SRP y SoC trabajan juntos para separar las preocupaciones. Son exactamente iguales a bajo nivel
fuente
Aquí está mi comprensión de estos principios.
Separación de preocupaciones (SoC) : se trata de dividir un sistema de software en módulos más pequeños, cada uno de estos módulos es responsable de una sola preocupación. Una preocupación, en este caso, es una característica o un caso de uso de un sistema de software. Como resultado, un módulo tiene una API (interfaz) bien definida, lo que hace que todo un sistema sea altamente cohesivo. Hay dos tipos principales: horizontal y vertical.
Principio de responsabilidad única (SRP) : es un principio de diseño que establece que cada componente básico (puede ser una clase, un módulo, un objeto o incluso una función) de un sistema debe tener una sola responsabilidad. Robert C. Martin. Martin describe una responsabilidad como una razón para cambiar. En general, es mucho mejor tener una sola clase / objeto que tenga responsabilidad sobre una sola parte de la funcionalidad en lugar de poder realizar muchas funciones, a veces incluso no relacionadas, haciendo que esta clase sea grande y estrechamente acoplada, así que llamado "objeto de Dios".
También describí estos principios en mayor detalle en mi blog, por favor, eche un vistazo.
https://crosp.net/blog/software-architecture/srp-soc-android-settings-example/
fuente