Public Data members vs Getters, Setters

Obecnie pracuję w Qt i so C++. Mam zajęcia, które mają prywatnych członków danych i publicznych członków funkcji. Mam publiczne gettery i settery dla członków danych dostępnych w klasie.

Teraz moje pytanie brzmi, jeśli mamy gettery i settery dla członków danych w naszych klasach, to jaki jest sens robienia tych członków danych jako prywatnych?Zgadzam się, że prywatne dane w klasach bazowych brzmią logicznie. Ale poza tym, posiadanie prywatnych członków i tak ich gettery i setery nie wydają mi się logiczne.

Lub zamiast Czy możemy upublicznić wszystkie zmienne tak, aby w ogóle nie były potrzebne gettery i settery? Czy to dobra praktyka? wiem, że posiadanie prywatnych członków zapewnia abstrakcję danych, ale posiadanie getterów i setterów pozwala na łatwy dostęp do tych zmiennych. Wszelkie wskazówki dotyczące tego są mile widziane.

Author: liaK, 2010-06-04

15 answers

Żadne. Powinieneś mieć metody, które robią różne rzeczy. Jeśli któraś z tych rzeczy odpowiada określonej zmiennej wewnętrznej, to jest świetne, ale nie powinno być nic, co Telegraph to do użytkowników swojej klasy.

Prywatne dane są prywatne, więc możesz zastąpić implementację w dowolnym momencie (i możesz wykonać pełne przebudowy, ale to inna sprawa). Gdy wypuścisz dżina z butelki, nie będziesz mógł go wepchnąć z powrotem.

EDIT: po komentarzu Doszedłem do innej odpowiedzi.

Chodzi mi o to, że zadajesz złe pytanie. Nie ma najlepszych praktyk w odniesieniu do korzystania z getterów/setterów lub posiadania członków publicznych. Jest tylko to, co jest najlepsze dla konkretnego obiektu i jak modeluje jakąś konkretną rzecz w świecie rzeczywistym (lub wyimaginowaną rzecz, być może w przypadku gry).

Osobiście getters / setters są mniejszym z dwóch zła. Ponieważ gdy zaczniesz tworzyć gettery / settery, ludzie przestają projektować obiekty krytycznym okiem jakie dane powinny być widoczne, a jakie nie. Z członkami publicznymi jest jeszcze gorzej, ponieważ tendencja staje się upublicznianiem wszystkiego.

Zamiast tego zbadaj, co robi obiekt i co oznacza, że coś jest tym obiektem. Następnie utwórz metody, które zapewniają naturalny interfejs do tego obiektu. To, że naturalny interfejs wymaga ujawnienia niektórych wewnętrznych właściwości za pomocą getterów i setterów, tak będzie. Ale ważne jest to, że myślałeś o tym wcześniej. i stworzył gettery/settery z uzasadnionego powodu projektowego.

 68
Author: jmucchiello,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-04 20:16:15

Nie, to nawet nie jest to samo.

Istnieją różne poziomy ochrony/ukrywania implementacji, które można osiągnąć poprzez różne podejścia do interfejsu klasy:


1. Public data member:

  • zapewnia zarówno odczyt, jak i zapis (jeśli nie const) dostęp do elementu danych
  • ujawnia fakt, że obiekt data fizycznie istnieje i jest fizycznie członkiem tej klasy (pozwala na tworzenie wskaźników typu pointer-to-member do tych danych member)
  • zapewnia lvalue dostęp do elementu danych (pozwala na tworzenie zwykłych wskaźników do elementu)


2. Metoda zwracająca odwołanie do fragmentu danych (ewentualnie do prywatnego członka danych):

  • zapewnia zarówno odczyt, jak i zapis (jeśli nie const) dostęp do danych
  • ujawnia fakt, że obiekt danych istnieje fizycznie, ale nie ujawnia , że jest fizycznie członkiem tej klasy (nie pozwala na tworzenie wskaźników Typ pointer-to-member do danych)
  • zapewnia lvalue dostęp do danych (pozwala na tworzenie zwykłych wskaźników do nich)


3. Metody Getter i / lub setter (możliwe uzyskanie dostępu do prywatnego elementu danych):

  • zapewnia zarówno dostęp do odczytu i/lub zapisu właściwości
  • nie ujawnia faktu, że obiekt danych fizycznie istnieje, nie mówiąc już fizycznie obecny w tej klasie (nie pozwala na tworzenie wskaźników typu pointer-to-member do tego dane, lub wszelkiego rodzaju wskaźniki w tym zakresie)
  • nie zapewnia lvalue dostępu do danych (nie pozwala na tworzenie zwykłych wskaźników do nich)

Podejście getter / setter nie ujawnia nawet faktu, że właściwość jest zaimplementowana przez obiekt fizyczny. Oznacza to, że za parą getter/setter nie może znajdować się żaden element danych fizycznych.

Biorąc powyższe pod uwagę, dziwne jest, że ktoś twierdzi, że para getter i setter jest taka sama jak public data member. W rzeczywistości nie mają ze sobą nic wspólnego.

Oczywiście, istnieją różne podejścia. Na przykład metoda getter może zwrócić odniesienie const do danych, które umieściłoby je gdzieś pomiędzy (2) i (3).

 33
Author: AnT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-19 01:50:34

Jeśli masz gettery i settery dla każdej pozycji danych, nie ma sensu, aby dane były prywatne. Dlatego posiadanie getterów i setterów dla każdej z pozycji danych jest złym pomysłem. Rozważ klasę std:: string-ma ona (prawdopodobnie) jeden getter, funkcję size () i w ogóle nie ma ustawiaczy.

Lub rozważmy obiekt BankAccount - czy powinniśmy mieć seter SetBalance() do zmiany bieżącego balansu? Nie, większość banków nie podziękuje Ci za wdrożenie czegoś takiego. Zamiast tego chcemy coś w rodzaju ApplyTransaction( Transaction & tx ).

 23
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-04 19:17:08

Upublicznij dane. W (raczej mało prawdopodobnym) przypadku, gdy pewnego dnia będziesz potrzebował logiki w "getter" lub "setter", możesz zmienić typ danych na klasę proxy, która przeciąża operator= i/lub operator T (Gdzie t=jakikolwiek typ używasz teraz), aby zaimplementować niezbędną logikę.

Edit: pomysł, że kontrolowanie dostępu do danych stanowi enkapsulację, jest w zasadzie fałszywy. Enkapsulacja polega na ukrywaniu szczegółów implementacji (w ogóle!) Nie kontrolowanie dostępu do data.

Enkapsulacja jest komplementarna do abstrakcji: abstrakcja zajmuje się zewnętrznie widocznym zachowaniem obiektu, podczas gdy enkapsulacja zajmuje się ukrywaniem szczegółów tego, jak to zachowanie jest zaimplementowane.

Użycie gettera lub settera w rzeczywistości zmniejsza poziom abstrakcji i eksponuje implementację-wymaga, aby kod klienta był świadomy, że ta konkretna klasa implementuje to, co jest logicznie "danymi" jako parę funkcji (getter i setter). Korzystanie z proxy jak już zasugerowałem powyżej zapewnia rzeczywistą enkapsulację-z wyjątkiem jednego niejasnego przypadku narożnego, całkowicie ukrywa fakt, że to, co jest logicznie fragmentem danych, jest faktycznie zaimplementowane za pomocą pary funkcji.

Oczywiście, należy to zachować w kontekście: dla niektórych klas "dane" wcale nie są dobrą abstrakcją. Ogólnie rzecz biorąc, jeśli możesz podać operacje wyższego poziomu zamiast danych, jest to preferowane. Niemniej jednak są zajęcia dla która najbardziej użyteczną abstrakcją jest odczytywanie i zapisywanie danych - a kiedy tak się dzieje, (abstrakcyjne) dane powinny być widoczne, tak jak wszystkie inne dane. Fakt, że uzyskanie lub ustawienie wartości może obejmować więcej niż zwykłe kopiowanie bitów, jest szczegółem implementacji, który powinien być ukryty przed użytkownikiem.

 11
Author: Jerry Coffin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-04 19:33:25

Gettery i Settery pozwalają na zastosowanie logiki do wejścia/wyjścia od prywatnych członków, dzięki czemu kontrolują dostęp do danych (enkapsulacja dla tych, którzy znają swoje warunki OO).

Zmienne publiczne pozostawiają dane twojej klasy otwarte dla publiczności w celu niekontrolowanej i niezatwierdzonej manipulacji, która prawie zawsze jest niepożądana.

Musisz myśleć o tych rzeczach długoterminowo, jak również. Możesz nie mieć teraz walidacji (dlatego publiczne zmienne wydają się być dobrym pomysłem), ale jest szansa, że zostaną dodane po drodze. Dodanie ich z wyprzedzeniem pozostawia framework, więc jest mniej ponownego faktoringu w dół raod nie wspominając o walidacji nie złamie zależny kod w ten sposób).

Pamiętaj jednak, że nie oznacza to, że każda prywatna zmienna potrzebuje własnego gettera/settera. Neil przywołuje dobry punkt w swoim przykładzie bankowym, że czasami Getters / Setters po prostu nie mają sensu.

 9
Author: Justin Niessner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-04 19:20:27

Jeśli jesteś pewien, że twoja logika jest prosta i nigdy nie musisz robić czegoś innego podczas czytania / pisania zmiennej, lepiej zachować dane publiczne. W przypadku C++ wolę używać struct zamiast klasy, aby podkreślić fakt, że dane są publiczne.

Jednak dość często trzeba zrobić inne rzeczy podczas uzyskiwania dostępu do danych członków, lub chcesz dać sobie swobodę, aby dodać tę logikę później. W tym przypadku dobrym pomysłem są gettery i setery. Twoja zmiana będzie przejrzysta do klientów Twojego kodu.

Prosty przykład dodatkowej funkcjonalności - możesz chcieć zalogować ciąg debugowania za każdym razem, gdy uzyskasz dostęp do zmiennej.

 5
Author: Igor Krivokon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-04 19:16:44

Oprócz problemów z hermetyzacją (które są wystarczającym powodem), bardzo łatwo jest ustawić punkt przerwania, gdy zmienna jest ustawiona / dostępna, gdy masz gettery / settery.

 5
Author: BlueRaja - Danny Pflughoeft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-04 19:18:14

Powody, dla których warto używać publicznych pól zamiast getterów i setterów, to:

  1. nie ma nielegalnych wartości.
  2. oczekuje się, że klient go edytuje.
  3. aby móc pisać rzeczy takie jak obiekt.X. Y = Z.
  4. do złożenia silnej obietnicy, że wartość jest tylko wartością i nie ma żadnych skutków ubocznych związanych z nią (i nie będzie w przyszłości).

W zależności od tego, na jakim oprogramowaniu pracujesz, mogą to być naprawdę wyjątkowe przypadki (i jeśli uważasz, że natknąłeś się na jeden, prawdopodobnie się mylisz) lub mogą one występować cały czas. To zależy.

(z dziesięć pytań dotyczących programowania opartego na wartościach.)

 4
Author: Ian Goldby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-25 14:07:14

Na ściśle praktycznej podstawie, sugeruję zacząć od uczynienia wszystkich członków danych prywatnymi, i uczynić ich getterów i setterów prywatnymi. Gdy dowiesz się, czego potrzebuje Reszta świata (tj. twoja "(l)społeczność użytkowników"), możesz ujawnić odpowiednie gettery i / lub settery lub napisać odpowiednio kontrolowane publiczne Accesory.

Również (na korzyść Neila), w czasie debugowania czasem warto mieć dogodne miejsce do powieszenia debugujących wydruków, a inne działania, gdy dany element danych jest odczytywany lub zapisywany. Z geterami i seterami jest to łatwe. Z publicznymi członkami danych, jest to ogromny ból w tylnej części.

 3
Author: John R. Strohm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-04 19:16:06

Zawsze myślałem, że gettery i settery są celowo gadatliwe w większości języków programowania, specjalnie po to, aby skłonić cię do zastanowienia się dwa razy nad ich użyciem - dlaczego twój rozmówca musi wiedzieć o wewnętrznym działaniu twojej klasy powinno być pytanie na przodzie twojego umysłu.

 2
Author: blissapp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-04 19:27:33

Uważam, że używanie getterów i setterów po prostu do pobierania i ustawiania wartości jest bezużyteczne. Nie ma różnicy między członkiem publicznym a prywatnym z takimi metodami. Używaj getterów i setterów tylko wtedy, gdy musisz w jakiś sposób kontrolować wartości lub gdy uważasz, że może to być przydatne w przyszłości (dodanie logiki nie spowoduje edycji reszty kodu).

Jako odniesienie przeczytaj C++ guidelines (C. 131)

 2
Author: Hitokage,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-10 16:52:28

Sugeruję, że nie masz publicznych członków danych(z wyjątkiem struktur POD). Nie polecam również, aby mieć gettery i settery dla wszystkich członków danych. Raczej zdefiniuj czysty publiczny interfejs dla swojej klasy. Może to obejmować metody, które pobierają i / lub ustawiają wartości właściwości, a te właściwości mogą być zaimplementowane jako zmienne składowe. Ale nie rób getterów i seterów dla wszystkich swoich członków.

Chodzi o to, aby oddzielić interfejs od implementacji, pozwala na modyfikację implementacji bez konieczności zmiany kodu przez użytkowników klasy. Jeśli ujawniasz wszystko za pomocą getterów i setterów, nie poprawiłeś niczego w porównaniu z używaniem publicznych danych.

 1
Author: Fred Larson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-04 19:14:36

Użycie getterów i setterów pozwoli Ci zmodyfikować sposób przekazywania wartości użytkownikowi.

Rozważ co następuje:

double premium;
double tax;

Następnie piszesz kod wszędzie używając tej premium wartości, aby uzyskać premium:

double myPremium = class.premium;

Twoje specyfikacje właśnie się zmieniły i premium z punktu widzenia użytkownika musi być premium + tax

Będziesz musiał zmodyfikować wszędzie, że ta wartość premium jest używana w Twoim kodzie i dodać do niej tax.

If instead you zaimplementowano go jako taki:

double premium;
double tax;

double GetPremium(){return premium;};

Cały Twój kod będzie używany GetPremium(), a twoja tax zmiana będzie jedną linijką:

double premium;
double tax;

double GetPremium(){return premium + tax;};
 1
Author: Ben Burnett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-04 19:33:33

Wartość zwracana wpływa również na użycie getterów i setterów. Różnicą jest uzyskanie wartości zmiennej lub uzyskanie dostępu do prywatnej zmiennej członkowskiej danych. By-value zachowuje integralność, by-reference lub by-pointer nie tak bardzo.

 0
Author: DaClown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-04 19:15:59

Gettery i Settery istnieją przede wszystkim po to, abyśmy mogli kontrolować, jak członkowie są pobierani i jak są ustawiani. Gettery i settery nie istnieją tylko jako sposób na dostęp do konkretnego członka, ale aby upewnić się, że zanim spróbujemy ustawić członka, że może on spełniać pewne warunki, lub jeśli go pobierzemy, możemy kontrolować, że zwracamy kopię tego członka w przypadku nie-prymitywnego typu. Ogólnie rzecz biorąc, powinieneś spróbować użyć G / S ' er, gdy chcesz potokować sposób interakcji członka danych z, bez nich spowodowałoby, że członek jest używany w sposób adhoc.

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-27 19:28:31