Jaka jest różnica między zasadą pojedynczej odpowiedzialności a oddzieleniem obaw

19

a) Jaka jest różnica między SRP a SoC ? Być może SRP jest stosowany na poziomie klasy, podczas gdy SoC może być stosowany na poziomie systemu , podsystemu , modułu , klasy lub funkcji .

b) Jeśli odpowiedź na a) brzmi „tak”, to czy SoC jest stosowany na poziomie klasy jako synonim SRP ?

Dziękuję Ci

użytkownik1483278
źródło

Odpowiedzi:

13

Zasada Pojedynczej Odpowiedzialności dotyczy tego, że Twój kod wykonuje tylko jedną czynność i możesz podzielić całą funkcjonalność na kilka klas, z których wszystkie przeznaczone są do wykonania jednej konkretnej rzeczy. Przykładem jest konkretna klasa do sprawdzania poprawności, wykonywania logiki biznesowej, wzbogacania modelu, pobierania danych, aktualizowania danych, nawigacji itp.

Separation of Concerns dotyczy tego, że Twój kod nie jest ściśle powiązany z niektórymi innymi klasami / systemami. Używanie interfejsów w kodzie bardzo pomaga, w ten sposób możesz luźno połączyć klasy / systemy z kodem. Zaletą tego jest to, że łatwiej jest również przetestować kod jednostkowo. Istnieje wiele frameworków (IoC), które mogą ci w tym pomóc, ale oczywiście możesz sam to zaimplementować.

Przykład czegoś SoC, ale bez 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();
    }
}

Jak widać, ten kod nie jest ściśle powiązany z klasami lub innymi systemami, ponieważ używa tylko niektórych interfejsów do robienia różnych rzeczy. Jest to dobre z punktu widzenia SoC.

Jak widać, klasa ta zawiera również 3 prywatne metody, które wykonują wymyślne rzeczy. Z punktu widzenia SRP metody te powinny być prawdopodobnie umieszczone w niektórych własnych klasach. 2 z nich robi coś z nawigacją, która pasowałaby do klasy INavigation. Drugi wykonuje kilka fantazyjnych obliczeń na przedmiocie, prawdopodobnie można go umieścić w klasie IBusinessLogic.

Mając coś takiego, oboje macie SoC i SRP na miejscu:

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();
    }
}

Oczywiście możesz debatować, czy cała ta logika powinna być umieszczona w GetDataAndNavigateSomewhereIfValidmetodzie. To jest coś, o czym powinieneś sam zdecydować. Dla mnie wygląda na to, że ta metoda robi zbyt wiele rzeczy.

Jan_V
źródło
„Po przeczytaniu pełnego postu w odpowiedzi JB Kinga myślę, że to również dobry post”. Ale odpowiedź JB Kinga jest przeciwna twojej odpowiedzi - mianowicie, że SoC dotyczy również pojedynczej odpowiedzialności, tyle że można ją zastosować na wyższych poziomach niż SRP
użytkownik1483278
2

Jeśli chodzi o stosowanie SRP tylko na poziomie klasowym, w swoich książkach Robert C. Martin (o ile wiem, spopularyzował, jeśli nie wpadł na ten pomysł) stwierdza:

Wyczyść kod, strona. 138 : „Zasada pojedynczej odpowiedzialności (SRP) stanowi, że klasa lub moduł powinien mieć jeden i tylko jeden powód do zmiany”.

W Agile Principles, Patterns and Practices in C #, str. 116 : „[...] i odnoszą spójność do sił, które powodują zmianę modułu lub klasy”.

Podkreśl moje.

W APPP bardziej szczegółowo mówi o SRP i skupia się prawie całkowicie na poziomie klasy. Chociaż wydaje się, że koncentruje się na poziomie klasy, uważam, że zasada dotyczy również modułów i innych konstrukcji wyższego poziomu.

Z tego powodu nie kwalifikowałbym SRP jako SoC na poziomie klasy, jak sugerujesz w swoim pytaniu.

Gilles
źródło
Więc jeśli założymy, że SRP może być również stosowany na wyższych poziomach, to różnica między SRP a SoC polega na tym, że SRP ponosi jedną odpowiedzialność, podczas gdy SoC może mieć zestaw ściśle powiązanych obowiązków?
user1483278
@ user1483278: Dobrze znam SRP, ale po raz pierwszy usłyszałem o SoC podczas czytania tego pytania, więc nie mogę odpowiedzieć na pytanie w twoim komentarzu. Z semantyki wygląda na to, że SRP dotyczy 1 odpowiedzialności i oddzielnych obaw SoC. Wiem, że jest to pedantyczna odpowiedź, ale w przypadku innych zasad stosowanie podobnych zasad daje podobne wyniki.
Gilles
0

Tutaj znajdziesz krótki film wyjaśniający wyraźnie różnicę między tymi terminologiami. https://www.youtube.com/watch?v=C7hkrV1oaSY

Rozdzielenie obaw (SoC). Podziel swoją aplikację na odrębne funkcje przy minimalnym nakładaniu się funkcjonalności. (Microsoft).

„Zaniepokojenie” = „wyraźna cecha” = „odrębna sekcja”

„Koncern” działa zarówno na wysokim, jak i na niskim poziomie

Zasada pojedynczej odpowiedzialności stanowi, że każdy moduł lub klasa powinna ponosić odpowiedzialność za jedną część funkcjonalności zapewnianej przez oprogramowanie i że odpowiedzialność powinna być całkowicie zamknięta w klasie. Wszystkie jego usługi powinny być ściśle dostosowane do tej odpowiedzialności. (Definicja Wikipedii)

„Odpowiedzialność” = „powód do zmiany”

zmienić co? „Pojedyncza część funkcji zapewnianych przez oprogramowanie” = jednostka podstawowa

Wniosek

Zasada pojedynczej odpowiedzialności działa na podstawowych jednostkach -> działa na niskim poziomie

Rozdział obaw dotyczy zarówno wysokiego, jak i niskiego poziomu

SRP i SoC współpracują w celu rozdzielenia problemów. Są dokładnie takie same na niskim poziomie

Marco Crispino
źródło
0

Oto moje rozumienie tych zasad.

Separation of Concerns (SoC) - polega na podzieleniu systemu oprogramowania na mniejsze moduły, każdy z tych modułów odpowiada za jeden problem. W tym przypadku problemem jest funkcja lub przypadek użycia systemu oprogramowania. Moduł ma dobrze zdefiniowany interfejs API (interfejs), dzięki czemu cały system jest bardzo spójny. Istnieją dwa główne typy: poziomy i pionowy.

Zasada pojedynczej odpowiedzialności (SRP) - jest zasadą projektową, która stwierdza, że ​​każdy blok konstrukcyjny (może to być klasa, moduł, obiekt, a nawet funkcja) systemu powinien ponosić tylko jedną odpowiedzialność. Robert C. Martin. Martin opisuje odpowiedzialność jako przyczynę zmiany. Ogólnie rzecz biorąc, o wiele lepiej jest mieć jedną klasę / obiekt, który odpowiada za jedną część funkcjonalności, zamiast wykonywać wiele, czasem nawet niepowiązanych, funkcji, dzięki czemu ta klasa jest duża i ściśle powiązana, a więc- zwany „przedmiotem Boga”.

Opisałem te zasady bardziej szczegółowo w moim poście na blogu, proszę spojrzeć.

https://crosp.net/blog/software-architecture/srp-soc-android-settings-example/

CROSP
źródło