Le principe de responsabilité unique est que votre code ne fait qu'une seule chose et vous pouvez diviser toutes les fonctionnalités en plusieurs classes qui sont toutes destinées à faire 1 chose spécifique. Un exemple est une classe spécifique pour la validation, faire de la logique métier, enrichir un modèle, récupérer des données, mettre à jour des données, navigation, etc.
La séparation des préoccupations concerne le fait que votre code n'est pas étroitement couplé à d'autres classes / systèmes. L'utilisation d'interfaces dans votre code aide beaucoup, de cette façon, vous pouvez coupler de manière lâche les classes / systèmes à votre code. Un avantage de cela est qu'il est plus facile de tester également votre code. Il existe de nombreux frameworks (IoC) qui peuvent vous aider à y parvenir, mais vous pouvez également implémenter une telle chose vous-même.
Un exemple de quelque chose de SoC, mais sans 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();
}
}
Comme vous pouvez le voir, ce code n'est pas étroitement couplé à des classes ou à d'autres systèmes, car il n'utilise que certaines interfaces pour faire des choses. C'est bon d'un point de vue SoC.
Comme vous pouvez le voir, cette classe contient également 3 méthodes privées qui font des choses fantaisistes. D'un point de vue SRP, ces méthodes devraient probablement être placées dans certaines classes qui leur sont propres. 2 d'entre eux font quelque chose avec la navigation, ce qui correspondrait à une classe d'INavigation. L'autre fait quelques calculs fantaisistes sur un élément, cela pourrait probablement être placé dans une classe IBusinessLogic.
Ayant quelque chose comme ça, vous avez tous les deux le SoC et le SRP en place:
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();
}
}
Bien sûr, vous pourriez débattre si toute cette logique devrait être placée dans la GetDataAndNavigateSomewhereIfValid
méthode. C'est quelque chose que vous devez décider vous-même. Pour moi, il semble que cette méthode fasse beaucoup trop de choses.