Kiedy się korzysta z modyfikatora "private"?

Odpowiedz Nowy wątek
2019-08-26 03:16
0

Co oznacza modyfikator private w języku C# można znaleźć z łatwością. Ale zastanawia mnie fakt, po co się go w ogóle używa? W jednej z książek o testowaniu znalazłem cytat:

R. Osharove napisał(a):

Metody prywatne lub chronione - zazwyczaj zgodnie z tym, co myśli deweloper - nie bez powodu są prywatne. Czasami chodzi o to, aby ukryć szczegóły implementacji, tak aby później można było zmienić implementację, nie zmieniając ostatecznej funkcjonalności. Może to być również związane z bezpieczeństwem lub dotyczyć ochrony kodu (na przykład zaciemniania).

VS2017 (nie jestem pewien co do poprzednich wersji) przy automatycznym generowaniu metod domyślnie tworzy je jako private. Można by pomyśleć "hmm, chyba tak jest lepiej". Ale dlaczego lepiej? Przecież publiczne metody są testowalne i dostępne z innych klas. W takim razie w jakim celu je ukrywać dla innych klas? Rozumiem, że proste funkcje, lub funkcje które jedynie korzystają z biblioteki/frameworka nie wymagają testowania i mogą pozostać prywatne. Ale dalej ciekaw jestem, po co? Można też refaktoryzować większe metody na mniejsze prywatne, ale czemu mają być prywatne?

Podsumowując, co może się stać złego jak metoda będzie publiczna? W jakich sytuacjach jest to niebezpieczne?

testuje się zewnętrzne funkcjonalności, czyli 'public' - AnyKtokolwiek 2019-08-26 10:24

Pozostało 580 znaków

2019-08-26 04:04
4

Metody prywatne są używane przez publiczne. Po prostu jak chcesz metodę publiczną rozbić na drobne czytelne kawałeczki, to sobie robisz kilka prywatnych metod, które używa ta publiczna.
Ale czemu do tych drobnych podzadań ma mieć ktoś dostęp z zewnątrz? Zwłaszcza jeśli te zadania wykonane wybiórczo mogą zaszkodzić działaniu zadaniu realizowanemu przez daną klasę? Np. zmienisz wartości pól, które powinny być zmienione razem z innymi polami, aby wszystkie dane dotyczyły tego samego przebiegu algorytmu. Np. metoda publiczna SetData z odpowiednimi argumentami wywoła kilka metod prywatnych, które przetworzą/wstawią dane z argumentów w odpowiednie pola, w odpowiedniej kolejności. Jeśli programista korzystający z tej klasy mógłby skorzystać z metod prywatnych, to jest szansa, że narobiłby bajzel, odpalając różne metody w złej kolejności i nie mógłby dojść, co jest przyczyną. Więc lepiej zrobić publiczną, idiotoodporną metodę, zamiast pisać w dokumentacji, żeby ładować dane do klasy w takiej i takiej kolejności...

edytowany 6x, ostatnio: Spine, 2019-08-26 09:11
Czyli to jest tylko kwestia zminimalizowania szansy wystąpienia ewentualnych błędów wykorzystania metody, a nie dostępu do nich przez osoby trzecie? - bakunet 2019-08-26 04:19
No wiesz... Czemu miałbym chcieć utrudniać osobom trzecim dostęp do jakiejś metody? Raz, że ktoś może sobie sam upublicznić daną metodę. Dwa, że zawartość metod to zazwyczaj nie jest jakaś wybitna, chroniona treść ;) - Spine 2019-08-26 09:19

Pozostało 580 znaków

2019-08-26 06:21
5

Robisz metode publiczną, jeśli jest powód, żeby ją upubliczniać, podzielić się nią ze światem. Jeśli jest używana tylko w swojej klasie to nie ma sensu jej upubliczniać a nawet nie powinno się :) z takich podstawowych publiczntch to na pewno metody implementujące interfejs, jakieś utilsy/commonsy

edytowany 1x, ostatnio: baant, 2019-08-26 06:23

Pozostało 580 znaków

2019-08-26 08:58
3

Gdyby była klasa nazwijmy ją Kitchen i udostępnia ona jedną publiczną metodę BakeACake(), z której mogą korzystać inne klasy.
Natomiast klasa Kitchen posiada kilka metod prywatnych, z których nie powinny korzystać inne klasy np:
kneadTheDough()
layOutTheDoughOnTheBakingTray()
putSomeIngredientsruitOnTheCake
bakeACake()

Wówczas metoda publiczna, BakeACake() mogłaby wyglądać mniej więcej tak:

bool BakeACake()
{
  bool result = false;

  result = kneadTheDough();

  if( result == true )
    result = layOutTheDoughOnTheBackingTray();

  if( result == true )
    putSomeIngredientsOnTheCake();

  if( result == true )
    result = bakeACake();

  return result;
}

Wyobraź sobie, że twoja klasa piecze ciasto z owocami (tak zaimplementowałeś metodę putSomeIngredientsOnTheCake, że kładzie na ciasto owoce). Jednak chcesz to zmienić, żeby robiła sernik. Wtedy zmieniasz implementację tej metody, a kod "na około" zostaje taki sam. Czyli z wielu miejsc nadal wołasz BakeACake(). To tylko taki prosty przykład, mam nadzieję, że może coś wyjaśnił.

Swoją drogą - nieświadomie napisałem metodę publiczną z wielkiej litery BakeACake(), natomiast metody prywatne z małej kneadTheDough(). To również się stosuje i polecam to stosować. - wyebani 2019-08-26 09:07
Mogę się mylić, ale w C# dla nazw wszystkich metod, bez względu na modyfikator dostępu, stosuje się konwencję Pascala. Ale dzięki za tip. - bakunet 2019-08-26 09:15
Być może, nie orientuję się. Na codzień pracuję w C++ i w firmie gdzie pracuję taka konwencja jest stosowana i o ile się nie mylę to pochodzi ona z notacji węgierskiej? No a wątek jest w dziale Inżynieria oprogramowania. - wyebani 2019-08-26 12:33
Jasne, nie krytykuję, tylko zaznaczam, że nie skorzystam z camela w metodach prywatnych ;p - bakunet 2019-08-27 03:17

Pozostało 580 znaków

2019-08-26 09:17
3

Ja ujmę to, co napisane wyżej. Możemy mieć kod podzielony na małe metody, które są wywoływane w publicznych. Może się okazać, że metoda publiczna blokuje muteks a nie robią tego metody prywatne. Może tak być w przypadku klasy reprezentującej listę. Blokowanie muteksu nie jest potrzebne na samą alokację nowego obiektu, ale na moment dodania albo sprawdzania rozmiaru.
Jeszcze jeden przykład:

public class Window extends JFrame {
    private static final long serialVersionUID = 6594367122489466981L;

    public Window() {
        init("Nazwa okna");
    }

    public Window(String title) {
        init(title);
    }

    private void init(String title) {
        setTitle(title);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
    }
}

Mamy kawałek kodu powtarzający się w kilku miejscach. Może to być chociażby zmiana rozmieszczenia elementów GUI po dodaniu przycisku. Jak chcę dodać element do interfejsu, to nie ma potrzeby, żebym pamiętał o układzie.

Pozostało 580 znaków

2019-08-26 09:57

Publiczne metody stanowią pewien "kontrakt" na którym inni będą polegać. Jeśli twoja klasa miała publiczną metodę X to jest szansa że ktoś jej używa, szczególnie jeśli mówimy o jakiejś bibliotece. To oznacza że nie mozesz już tej klasy refaktorować, bo złamiesz kompatybilność wsteczną. Gdyby metoda była prywatna, tego problemu by nie było. Miałbyś klasyczną zaletę enkapsulacji -> masz publiczny interfejs i masz wewnętrzną implementacje, która moze sie zmieniać, o ile kontrakt pozostaje ten sam.
Generalnie udostępnianie szczegółów implementacyjnych to błąd, bo cementuje ci ten kod.


Masz problem? Pisz na forum, nie do mnie. Nie masz problemów? Kup komputer...

Pozostało 580 znaków

2019-08-26 10:13
1
bakunet napisał(a):

Podsumowując, co może się stać złego jak metoda będzie publiczna? W jakich sytuacjach jest to niebezpieczne?

Jeśli będzie publiczna, to pewnie ktoś ktoś prędzej czy później Ci jej użyje, przez co przy ewentualnych zmianach masz wiecej zabawy


Spring? Ja tam wole mieć kontrole nad kodem ᕙ(ꔢ)ᕗ
Haste - mała biblioteka do testów z czasem.

Pozostało 580 znaków

2019-08-26 11:39
0

Dzięki wszystkim za odpowiedzi. Poniższy akapit chyba najlepiej pozwolił mi zrozumieć, że metody publiczne, jako że implementują interfejsy, są dostępne z zewnątrz, są testowane, nie powinny być zmieniane i korzystają z prywatnych, które mogą być refaktoryzowane dla zachowania ogólnej funkcjonalności metody publicznej. A prywatne, jako że mogą podlegać zmianom, nie powinny być testowane, bo wtedy trzeba by było pisać w kółko testy, oraz ich funkcjonalność, gdyby była dostępna z zewnątrz, by się ciągle zmieniała. W sumie to mega dobrze to wiedzieć, trochę to wpłynie na moje podejście do kodu.

Shalom napisał(a):

Publiczne metody stanowią pewien "kontrakt" na którym inni będą polegać. Jeśli twoja klasa miała publiczną metodę X to jest szansa że ktoś jej używa, szczególnie jeśli mówimy o jakiejś bibliotece. To oznacza że nie mozesz już tej klasy refaktorować, bo złamiesz kompatybilność wsteczną.

edytowany 2x, ostatnio: bakunet, 2019-08-26 11:46

Pozostało 580 znaków

2019-08-26 12:10
3

A prywatne, jako że mogą podlegać zmianom, nie powinny być testowane

Powinny testować sie "automatycznie" kiedy testujesz publiczne API. W ogóle nie pisze się testów "metody" czy "klasy", bo to nie ma sensu. Pisze się testy dla konkretnego feature, konkretnej funkcjonalności którą dostarczasz. I one są właśnie określone przez API/kontrakt który udostępniasz.


Masz problem? Pisz na forum, nie do mnie. Nie masz problemów? Kup komputer...
edytowany 1x, ostatnio: Shalom, 2019-08-26 12:10

Pozostało 580 znaków

2019-08-26 13:11
1

Dodam jeszcze że chodzi o pewne podstawowe koncepcje OOP, w tym przypadku enkapsulacje. Mając prywatne metody ukrywamy szczegóły implementacji które dla użytkowników klasy nie mają znaczenia, a więc nie powinny być wystawiane publicznie. Pozwala to uniknąć wyżej wymienionych źródeł błędów.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.

Pozostało 580 znaków

2019-08-26 19:39
2

Ogólnie ten problem może być trudny do zrozumienia, gdy tworzysz małe aplikacje z prostą logiką pisane "na sztywno", czyli bez pomyślenia o dalszych modyfikacjach i rozbudowie. Gdy jednak kod rośnie jego utrzymanie robi się kłopotliwe to to wszystko zaczyna mieć znaczenie. Na to właśnie odpowiedzią miało być OOP. W OOP jest wiele rozwiązań i bardziej lub mniej formalnych zasad (SOLID, KISS, DRY YAGNI, LoD itp), które pozwalają pisać i utrzymywać duży kod.

O modyfikatorach metod lubię myśleć w ten sposób, że każdy modyfikator inny niż private stwarza pewien dług, dlatego że udostępniając w interfejsie klasy "coś" i musisz później to utrzymywać. Tutaj warto zauważyć, że klient kodu może mieć dostęp nie tylko do public ale i protected (przy dziedziczeniu), więc stosowanie protected też zwiększa ten dług (choć w zdecydowanie mniejszym stopniu niż public). Ja osobiście jako domyślny obecnie stosuje "private", a w pewnych sytuacjach (np. libka narzędziowa) protected aby nie utrudniać rozszerzania / modyfikowania innym. Staram się aby moje klasy udostępniały 1 metodę publiczną (pomijam tu obiekty DTO itp.) i jeśli jest ich więcej to staram się pomyśleć czy by nie podzielić na 2 klasy - ale oczywiście wszystko z rozsądkiem.

Niestety OOP to jest dość skomplikowany twór i wiele zasad opisywanych w podręcznikach mądrych ludzi trudno jest zrozumieć czy przyjąć na wiarę. Dopiero jak kilka razy wdepniesz w kupę w większym projekcie zaczynasz je doceniać i tak na prawdę rozumieć. Zawsze gdy już wydaje mi się, że rozumiem OOP to pojawia się nowy "level" i zmieniam spojrzenie na wiele rzeczy.

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0