Das Prinzip der Einzelverantwortung bezieht sich darauf, dass Ihr Code nur eine Aufgabe erfüllt. Sie können alle Funktionen in mehrere Klassen aufteilen, die alle für eine bestimmte Aufgabe vorgesehen sind. Ein Beispiel ist eine bestimmte Klasse zur Validierung, zum Ausführen von Geschäftslogik, zum Anreichern eines Modells, zum Abrufen von Daten, zum Aktualisieren von Daten, zur Navigation usw.
Bei der Trennung von Bedenken geht es darum, dass Ihr Code nicht eng an andere Klassen / Systeme gekoppelt ist. Die Verwendung von Schnittstellen in Ihrem Code hilft sehr, auf diese Weise können Sie Klassen / Systeme locker mit Ihrem Code koppeln. Ein Pluspunkt dabei ist, dass es einfacher ist, Ihren Code auch als Unit zu testen. Es gibt viele (IoC-) Frameworks, die Ihnen dabei helfen können, aber Sie können so etwas natürlich auch selbst implementieren.
Ein Beispiel für etwas SoC, aber ohne 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();
}
}
Wie Sie sehen können, ist dieser Code nicht eng an Klassen oder andere Systeme gekoppelt, da er nur einige Schnittstellen verwendet, um Dinge zu erledigen. Dies ist vom Standpunkt des SoC aus gesehen gut.
Wie Sie sehen können, enthält diese Klasse auch 3 private Methoden, die ausgefallene Dinge tun. Aus SRP-Sicht sollten diese Methoden wahrscheinlich in eigene Klassen eingeordnet werden. 2 von ihnen tun etwas mit der Navigation, was in eine Navigationsklasse passen würde. Der andere führt einige ausgefallene Berechnungen für ein Element durch, dies könnte wahrscheinlich in eine IBusinessLogic-Klasse eingefügt werden.
Wenn Sie so etwas haben, haben Sie beide den SoC und den SRP installiert:
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();
}
}
Natürlich könnte man diskutieren, ob all diese Logik in die GetDataAndNavigateSomewhereIfValid
Methode aufgenommen werden sollte. Das sollten Sie selbst entscheiden. Für mich sieht es so aus, als ob diese Methode viel zu viel Zeug macht.