Szukałem i znam teoretyczną różnicę.
- public - każda klasa / funkcja może uzyskać dostęp do metody / właściwości.
- chroniony - tylko ta klasa i wszystkie podklasy mogą uzyskać dostęp do metody / właściwości.
- private - tylko ta klasa może uzyskać dostęp do metody / właściwości. Nie zostanie nawet odziedziczona.
Wszystko w porządku, pytanie brzmi: jaka jest praktyczna różnica między nimi? Kiedy używałbyś private
i kiedy używałbyś protected
? Czy istnieje standardowa lub akceptowalna dobra praktyka w stosunku do tej?
Do tej pory, aby zachować koncepcję dziedziczenia i polimorfizmu, używam public
do wszystkiego, do czego można uzyskać dostęp z zewnątrz (jak konstruktory i funkcje głównych klas) oraz protected
do metod wewnętrznych (logika, metody pomocnicze itp.). Czy jestem na dobrej drodze?
(Zauważ, że to pytanie jest dla mnie, ale także dla przyszłego odniesienia, ponieważ nie widziałem pytania takiego jak to SO).
oop
language-agnostic
coding-style
Duch Madary
źródło
źródło
internal
w języku C #, który ogranicza poziom dostępu klasy lub jej członków w zestawie fizycznym. Chociaż nie jestem pewien, czy obsługuje je lub coś podobnego w innych językach.Odpowiedzi:
Nie, nie jesteś na dobrej drodze. Praktyczna zasada brzmi: uczyń wszystko tak prywatnym, jak to tylko możliwe. To sprawia, że twoja klasa jest bardziej hermetyzowana i pozwala na zmianę wewnętrznych elementów klasy bez wpływu na kod używający twojej klasy.
Jeśli zaprojektujesz klasę tak, aby była dziedziczona, ostrożnie wybierz to, co może być nadpisane i dostępne z podklas, i uczyń to chronionym (i na koniec, mówiąc o Javie, jeśli chcesz, aby była dostępna, ale nie można jej zastąpić). Należy jednak pamiętać, że gdy tylko zaakceptujesz posiadanie podklas swojej klasy i pojawi się chronione pole lub metoda, to pole lub metoda jest częścią publicznego interfejsu API klasy i nie można ich później zmienić bez zerwania podklas.
Klasa, która nie jest przeznaczona do dziedziczenia, powinna być ostateczna (w Javie). Możesz złagodzić niektóre reguły dostępu (od prywatnych do chronionych, od ostatecznych do nie ostatecznych) ze względu na testowanie jednostkowe, ale następnie udokumentuj to i wyjaśnij, że chociaż metoda jest chroniona, nie powinna być nadpisywana.
źródło
private
vsprotected
Kiedy chcę właściwością być dziedziczone, a kiedy nie? Naprawdę nie mogę stwierdzić, czy użytkownik czasami w przyszłości chce wziąć moją klasę i przedłużyć ją ...Pozwólcie, że poprzedzę to stwierdzeniem, że mówię tutaj przede wszystkim o dostępie do metod oraz w nieco mniejszym stopniu o oznaczaniu klas jako końcowych, a nie dostępie do elementów członkowskich.
Stara mądrość
miało sens w czasach, gdy zostało napisane, zanim open source zdominowało przestrzeń bibliotek programistów i zarządzanie VCS / zależnościami. stał się hiperwspółpracujący dzięki Githubowi, Mavenowi itp. W tamtych czasach można było również zarobić pieniądze, ograniczając sposób (-y) wykorzystania biblioteki. Prawdopodobnie pierwsze 8 lub 9 lat mojej kariery spędziłem na ścisłym przestrzeganiu tej „najlepszej praktyki”.
Dziś uważam, że to zła rada. Czasami istnieje rozsądny argument, aby oznaczyć metodę jako prywatną lub jako finał klasy, ale jest to niezwykle rzadkie, a nawet wtedy prawdopodobnie niczego nie poprawia.
Czy kiedykolwiek:
Oto trzy największe usprawiedliwienia, jakie słyszałem, dotyczące domyślnego oznaczania metod jako prywatnych:
Racjonalizacja nr 1: To niebezpieczne i nie ma powodu, aby zastępować określoną metodę
Nie mogę zliczyć, ile razy myliłem się co do tego, czy kiedykolwiek będzie potrzeba zastąpienia określonej metody, którą napisałem. Pracując nad kilkoma popularnymi bibliotekami open source, na własnej skórze poznałem prawdziwy koszt oznaczania rzeczy jako prywatnych. Często eliminuje jedyne praktyczne rozwiązanie nieprzewidzianych problemów lub przypadków użycia. I odwrotnie, nigdy od ponad 16 lat rozwoju zawodowego nie żałowałem oznaczenia metody chronionej zamiast prywatnej z powodów związanych z bezpieczeństwem API. Gdy programista decyduje się na rozszerzenie klasy i zastąpienie metody, świadomie mówi „Wiem, co robię”. a ze względu na produktywność powinno to wystarczyć. Kropka. Jeśli jest to niebezpieczne, zanotuj to w klasie / metodzie Javadocs, nie tylko na ślepo zatrzaskuj drzwi.
Metody znakowania chronione domyślnie są złagodzeniem dla jednego z głównych problemów współczesnego rozwoju oprogramowania: porażki wyobraźni.
Racjonalizacja nr 2: Utrzymuje publiczny interfejs API / Javadocs w czystości
Ten jest bardziej rozsądny iw zależności od grupy docelowej może być nawet właściwym rozwiązaniem, ale warto rozważyć, jaki jest koszt utrzymania „czystego” API: rozszerzalność. Z powodów wymienionych powyżej prawdopodobnie bardziej sensowne jest oznaczanie rzeczy chronionych domyślnie na wszelki wypadek.
Racjonalizacja # 3: Moje oprogramowanie jest komercyjne i muszę ograniczyć jego użycie.
Jest to również rozsądne, ale jako konsument wybrałbym za każdym razem mniej restrykcyjnego konkurenta (zakładając, że nie ma znaczących różnic w jakości).
Nigdy nie mów nigdy
Nie mówię, że nigdy nie oznaczaj metod jako prywatnych. Mówię, że lepszą praktyczną zasadą jest „ochrona metod, chyba że jest dobry powód, aby tego nie robić”.
Ta rada jest najbardziej odpowiednia dla osób pracujących nad bibliotekami lub projektami na większą skalę, które zostały podzielone na moduły. W przypadku mniejszych lub bardziej monolitycznych projektów nie ma to większego znaczenia, ponieważ i tak kontrolujesz cały kod i łatwo jest zmienić poziom dostępu do kodu, jeśli / kiedy go potrzebujesz. Mimo wszystko dałbym tę samą radę :-)
źródło
Rationalization # 1
- Kiedy oznaczam coś jako chronione, wybieram to wyraźnie, ponieważ czuję, że to zachowanie nie jest ostateczne i może być przypadkiem, w którym moje klasy podrzędne będą chciały je zastąpić. Jeśli nie jestem tego taki pewien, chciałbym domyślnie ustawić go jako prywatny. Szczególnie w języku takim jak C #, który domyślnie utrzymuje metodę niewirtualną, dodawanie samego specyfikatora dostępu chronionego nie ma sensu. Aby jasno określić cel, musisz dodać oba słowa kluczowevirtual
iprotected
słowa kluczowe. Ponadto ludzie wolą skojarzenia od dziedziczenia, więcprotected
domyślnie trudno jest dostrzecPrzestańcie nadużywać prywatnych pól !!!
Komentarze tutaj wydają się w przeważającej mierze popierające korzystanie z pól prywatnych. Cóż, mam coś innego do powiedzenia.
Czy pola prywatne są w zasadzie dobre? Tak. Ale mówienie, że złotą zasadą jest uczynienie wszystkiego prywatnym, gdy nie jesteś pewien, jest zdecydowanie błędne ! Nie zobaczysz problemu, dopóki go nie napotkasz. Moim zdaniem powinieneś oznaczyć pola jako chronione, jeśli nie masz pewności .
Istnieją dwa przypadki, w których chcesz rozszerzyć klasę:
W pierwszym przypadku nie ma nic złego w polach prywatnych. Fakt, że ludzie nadużywają prywatnych pól, sprawia, że frustrujące jest, gdy dowiadujesz się, że nie możesz modyfikować gówna.
Rozważ prostą bibliotekę modelującą samochody:
Autor biblioteki pomyślał: nie ma powodu, dla którego użytkownicy mojej biblioteki muszą mieć dostęp do szczegółów implementacji,
assembleCar()
prawda? Oznaczmy śrubkę jako prywatną.Cóż, autor się myli. Jeśli chcesz zmodyfikować tylko
assembleCar()
metodę bez kopiowania całej klasy do swojego pakietu, nie masz szczęścia. Musisz przepisać własnescrew
pole. Powiedzmy, że w tym samochodzie jest kilkanaście śrubek, a każda z nich zawiera jakiś nietrywialny kod inicjalizacyjny różnymi prywatnymi metodami, a wszystkie te śruby są oznaczone jako prywatne. W tym momencie zaczyna ssać.Tak, możesz się ze mną spierać, że autor biblioteki mógł napisać lepszy kod, więc nie ma nic złego w polach prywatnych . Nie twierdzę, że pole prywatne jest problemem z OOP . Jest to problem, gdy ludzie ich używają.
Morał z tej historii jest taki, że jeśli piszesz bibliotekę, nigdy nie wiesz, czy Twoi użytkownicy chcą uzyskać dostęp do określonej dziedziny. Jeśli nie masz pewności, zaznacz to,
protected
aby wszyscy byli później szczęśliwsi. Przynajmniej nie nadużywaj pola prywatnego .Bardzo popieram odpowiedź Nicka.
źródło
Niedawno przeczytałem artykuł, w którym mówiono o blokowaniu wszystkich zajęć tak często, jak to możliwe. Spraw, aby wszystko było ostateczne i prywatne, chyba że masz natychmiastową potrzebę ujawnienia niektórych danych lub funkcji światu zewnętrznemu. Zawsze łatwo jest rozszerzyć zakres, aby później było bardziej dopuszczalne, ale nie na odwrót. Najpierw rozważ zrobienie jak największej liczby rzeczy
final
, które uczynią wyboru pomiędzyprivate
iprotected
znacznie łatwiejsze.Teraz, jeśli zostanie ci ostatnia klasa, ustaw wszystko jako prywatne, chyba że coś jest absolutnie potrzebne światu - upublicznij to.
Jeśli zostanie ci klasa, która ma podklasy, dokładnie zbadaj każdą właściwość i metodę. Najpierw zastanów się, czy chcesz nawet ujawnić tę właściwość / metodę podklasom. Jeśli tak, zastanów się, czy podklasa może siać spustoszenie w obiekcie, jeśli zepsuła wartość właściwości lub implementację metody w procesie przesłonięcia. Jeśli to możliwe i chcesz chronić właściwość / metodę swojej klasy nawet przed podklasami (wiem, brzmi to ironicznie), uczyń ją prywatną. W przeciwnym razie zabezpiecz go.
Zastrzeżenie: nie programuję zbyt wiele w Javie :)
źródło
final class
w Javie to klasa, z której nie można dziedziczyć. Afinal method
nie jest wirtualny, tj. Nie można go zastąpić przez podklasę (metody Java są domyślnie wirtualne). Afinal field/parameter/variable
jest niezmiennym odwołaniem do zmiennej (w tym sensie, że nie można go zmodyfikować po zainicjowaniu).Kiedy używałbyś
private
i kiedy używałbyśprotected
?Prywatne dziedziczenie można traktować jako implementowane w kategoriach relacji, a nie relacji IS-A . Mówiąc najprościej, zewnętrzny interfejs klasy dziedziczącej nie ma (widocznego) związku z odziedziczoną klasą, wykorzystuje
private
dziedziczenie tylko do zaimplementowania podobnej funkcjonalności, jaką zapewnia klasa Base.W przeciwieństwie do dziedziczenia prywatnego, dziedziczenie chronione jest ograniczoną formą dziedziczenia, w której klasa pochodna IS-A jest rodzajem klasy bazowej i chce ograniczyć dostęp członków pochodnych tylko do klasy pochodnej.
źródło
Cóż, chodzi o hermetyzację, jeśli klasy paybill obsługują fakturowanie płatności, a następnie w klasie produktu, dlaczego miałby on potrzebować całego procesu fakturowania, tj. Metody płatności, jak zapłacić, gdzie zapłacić ... więc tylko zezwalając na to, co jest używane dla innych klas i obiektów nic poza tym publicznym dla tych, których inne klasy również używałyby, chronionym dla tych limitów tylko dla rozszerzających klas. Ponieważ jesteś madara uchiha, prywatny jest tak
"limboo"
, jak widzisz (prowadzisz tylko jedną klasę).źródło