Принцип единой ответственности заключается в том, что ваш код выполняет только одну задачу, и вы можете разделить всю функциональность на несколько классов, которые предназначены для выполнения одной конкретной задачи. Примером является конкретный класс для проверки, выполнения некоторой бизнес-логики, обогащения модели, извлечения данных, обновления данных, навигации и т. Д.
Разделение проблем заключается в том, что ваш код не тесно связан с некоторыми другими классами / системами. Использование интерфейсов в вашем коде очень помогает, таким образом вы можете свободно связывать классы / системы с вашим кодом. Плюсом этого является то, что ваш код также проще для модульного тестирования. Существует множество (IoC) фреймворков, которые могут помочь вам в этом, но вы, конечно, можете реализовать и это самостоятельно.
Пример чего-то SoC, но не имеющий 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();
}
}
Как вы можете видеть, этот код не тесно связан с классами или другими системами, потому что он использует только некоторые интерфейсы для работы. Это хорошо с точки зрения SoC.
Как вы можете видеть, этот класс также содержит 3 приватных метода, которые делают некоторые интересные вещи. С точки зрения SRP, эти методы, вероятно, должны быть помещены в некоторые собственные классы. 2 из них делают что-то с навигацией, что вписывается в некоторый класс INavigation. Другой выполняет некоторые необычные вычисления для элемента, возможно, его можно поместить в класс IBusinessLogic.
Имея что-то вроде этого, у вас обоих есть SoC и SRP:
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();
}
}
Конечно, вы могли бы спорить, следует ли поместить всю эту логику в GetDataAndNavigateSomewhereIfValid
метод. Это то, что вы должны решить для себя. Мне кажется, что этот метод делает слишком много вещей.