Nguyên tắc trách nhiệm duy nhất là về mã của bạn chỉ thực hiện 1 điều và bạn có thể phân chia tất cả các chức năng trong một số lớp, tất cả đều có nghĩa là để thực hiện 1 điều cụ thể. Một ví dụ là một lớp cụ thể để xác nhận, thực hiện một số logic nghiệp vụ, làm phong phú một mô hình, lấy dữ liệu, cập nhật dữ liệu, điều hướng, v.v.
Phân tách mối quan tâm là về mã của bạn không được liên kết chặt chẽ với một số lớp / hệ thống khác. Sử dụng các giao diện trong mã của bạn sẽ giúp ích rất nhiều, theo cách này bạn có thể kết nối một cách lỏng lẻo các lớp / hệ thống với mã của mình. Một điều khó khăn ở đây là việc kiểm tra mã của bạn cũng dễ dàng hơn. Có rất nhiều khung (IoC) có thể giúp bạn đạt được điều này, nhưng dĩ nhiên bạn cũng có thể thực hiện một điều như vậy.
Một ví dụ về một cái gì đó SoC, nhưng không có 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();
}
}
Như bạn có thể thấy, mã này không được kết hợp chặt chẽ với các lớp hoặc các hệ thống khác, bởi vì nó chỉ sử dụng một số giao diện để làm công cụ. Điều này là tốt từ quan điểm của SoC.
Như bạn có thể thấy lớp này cũng chứa 3 phương thức riêng thực hiện một số công cụ ưa thích. Từ quan điểm SRP, những phương thức đó có lẽ nên được đặt trong một số lớp của riêng chúng. 2 trong số họ làm một cái gì đó với điều hướng, sẽ phù hợp với một số lớp INavulation. Cái kia thực hiện một số tính toán ưa thích trên một mặt hàng, điều này có thể được đặt trong một lớp IBusinessLogic.
Có một cái gì đó như thế này, cả hai bạn đều có SoC và 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();
}
}
Tất nhiên bạn có thể tranh luận nếu tất cả logic này nên được đặt trong GetDataAndNavigateSomewhereIfValid
phương thức. Đây là điều bạn nên tự quyết định. Đối với tôi có vẻ như phương pháp này đang làm quá nhiều thứ.