Mam klasę ze zmienną, która jest prywatna, a klasa ma getter i setter dla tej zmiennej. Dlaczego nie upublicznić tej zmiennej?
Jedyny przypadek, który uważam, że musisz użyć programów pobierających i ustawiających, to konieczność wykonania operacji oprócz zestawu lub get. Przykład:
void my_class::set_variable(int x){
/* Some operation like updating a log */
this->variable = x;
}
this->variable = x + 5
lub wywołaćUpdateStatistics
funkcję settera, w takich przypadkachclassinstancea->variable = 5
spowoduje to problemy.set_inch
,set_centimeter
,get_inch
,get_centimeter
, niektóre straszne czyny.Odpowiedzi:
Czy słyszałeś kiedyś o nieruchomości?
Właściwość to pole, które ma „wbudowane” akcesoria (pobierające i ustawiające). Na przykład Java nie ma właściwości, ale zaleca się zapisanie programów pobierających i ustawiających w polu prywatnym. C # ma właściwości.
Dlaczego więc potrzebujemy getterów i seterów? Zasadniczo potrzebujemy go do ochrony / osłony pola. Na przykład nie uzyskujesz dostępu do pola w odwołaniu do pamięci, uzyskujesz dostęp do metody, która następnie zmieni pole (odwołanie). Ta metoda jest w stanie wykonać pewne operacje, których użytkownik nie chce poznać ( zachowanie enkapsulujące ), jak w twoim przykładzie. Wyobraź sobie na przykład, że kilkanaście klas korzysta z twojego pola publicznego i musisz zmienić sposób, w jaki jest on używany ... Musisz spojrzeć na każdą z tych klas, aby zmienić sposób, w jaki korzystają z pola ... Nie więc „OOlysh”.
Ale na przykład jeśli masz pole boolowskie o nazwie martwe. Powinieneś pomyśleć dwa razy, zanim zadeklarujesz setDead i isDead. Powinieneś napisać akcesory, które są czytelne dla człowieka , na przykład kill () zamiast setDead.
Istnieje jednak wiele frameworków, które zakładają, że przestrzegasz konwencji nazewnictwa JavaBean (tutaj mówię o Javie), dlatego w takich przypadkach powinieneś zadeklarować wszystkie pobierające i ustawiające po konwertowaniu nazw.
źródło
foo.bar = biz.baz+5
aby wywołać funkcjębiz
do ocenybaz
, a następnie dodać pięć do niej i wywołać funkcję wfoo
celu ustawieniabar
wartości wynikowej. Takie przeciążenia nie są nazywane „właściwościami”, ale mogą służyć temu samemu celowi.To nie jest najpopularniejsza opinia, ale nie widzę dużej różnicy.
Setery i gettery to dość zły pomysł. Zastanawiałem się nad tym i szczerze mówiąc, w praktyce nie mogę znaleźć różnicy między ustawiającym / pobierającym właściwość a zmienną publiczną.
W TEORII seter i getter lub właściwość dodają miejsce do podjęcia dodatkowych działań, gdy zmienna jest ustawiona / otrzymana i teoretycznie izolują twój kod od zmian.
W rzeczywistości rzadko widzę seterów i getterów używanych do dodawania akcji, a kiedy chcesz dodać akcję, chcesz dodać ją do WSZYSTKICH setterów lub getterów klasy (np. Rejestrowanie), co powinno sprawić, że pomyślisz, że powinna być lepszym rozwiązaniem.
Jeśli chodzi o izolowanie decyzji projektowych, jeśli zmienisz int na długi, nadal musisz zmienić seterów i przynajmniej sprawdzić każdą linię, która ma do nich dostęp ręcznie - nie ma tam dużej izolacji.
W każdym razie domyślnie należy unikać klas zmiennych, więc dodanie settera powinno być ostatecznością. Jest to ograniczane przez wzorzec konstruktora, w którym można ustawić wartość, dopóki obiekt nie znajdzie się w pożądanym stanie, wtedy klasa może stać się niezmienna, a Twoi seterzy będą zgłaszać wyjątki.
Co do getterów - wciąż nie mogę znaleźć dużej różnicy między getterem a publiczną zmienną końcową. Problem w tym, że w obu przypadkach jest to zły OO. Nie powinieneś prosić o wartość z obiektu i operować na nim - powinieneś prosić obiekt o wykonanie dla ciebie operacji.
Nawiasem mówiąc, w żaden sposób nie opowiadam się za zmiennymi publicznymi - mówię, że settery i gettery (a nawet właściwości) są zbyt bliskie, by już były zmiennymi publicznymi.
Dużym problemem jest po prostu to, że ludzie, którzy nie są programistami OO, są zbyt kuszeni, aby używać setterów i getterów do przekształcania obiektów w kule własności (struktury), które są przekazywane i obsługiwane, co jest odwrotnością działania kodu zorientowanego obiektowo.
źródło
Użytkownik programów pobierających i ustawiających stosuje się do zasady hermetyzacji . Pozwoli ci to zmienić sposób działania wewnątrz klasy i utrzymać wszystko w działaniu.
Na przykład, jeśli 3 inne obiekty wywołują,
foo.bar
aby uzyskać wartość paska, a ty zdecydujesz się zmienić nazwę paska tak daleko, że masz problem na rękach. Gdyby wywoływane obiektyfoo.bar
musiałyby zmienić wszystkie klasy, które to mają. Jeśli używany jest setter / getter, nie masz nic do zmiany. Inną możliwością jest zmiana typu zmiennej, w którym to przypadku wystarczy dodać kod transformujący do gettera / settera i wszystko jest w porządku.źródło
Korzystanie z metod pobierających i ustawiających umożliwia także kontrolowanie zawartości przechowywanej w określonej zmiennej. Jeśli treść musi być określonego typu lub wartości, częścią kodu ustawiającego może być upewnienie się, że nowa wartość spełnia te wymagania. Jeśli zmienna jest publiczna, nie możesz upewnić się, że te wymagania są spełnione.
Takie podejście sprawia również, że Twój kod jest łatwiejszy do dostosowania i zarządzania. Znacznie łatwiej jest wprowadzać zmiany w architekturze klasy, jeśli masz funkcje, które ukrywają tę architekturę przed wszystkimi innymi klasami lub funkcjami, które korzystają z tej klasy. Wspomniana już zmiana nazwy zmiennej jest tylko jedną z wielu wielu zmian, które są znacznie łatwiejsze do wprowadzenia, jeśli masz funkcje takie jak gettery i setters. Ogólnym pomysłem jest zachowanie jak największej prywatności, szczególnie zmiennych klas.
źródło
Mówisz „Jedynym przypadkiem, który myślę, że musisz użyć getterów i setterów, jest to, że musisz wykonać jakąś operację poza setem lub get.”.
Powinieneś użyć getterów i seterów, jeśli w pewnym momencie w przyszłości będziesz mógł zajść potrzeba wykonania operacji poza ustawieniem i pobieraniem i nie chcesz zmieniać tysięcy wierszy kodu źródłowego, kiedy to się stanie.
Powinieneś używać programów pobierających i ustawiających, jeśli nie chcesz, aby ktoś pobierał adres zmiennej i przekazywał ją, z katastrofalnymi konsekwencjami, jeśli zmienna ta może zostać zmieniona bez podania kodu źródłowego, a nawet po tym, jak obiekt przestał istnieć .
źródło
Po pierwsze, wyjaśnijmy paradygmat.
Gdzie przydatny jest getter / setter?
Czy metody pobierające / ustawiające są przydatne w strukturach danych? Nie.
Struktura danych to specyfikacja układu pamięci, która jest wspólna i manipulowana przez rodzinę funkcji.
Zasadniczo każda stara nowa funkcja może nadejść i manipulować strukturą danych, jeśli robi to w taki sposób, że inne funkcje nadal ją rozumieją, wówczas funkcja dołącza do rodziny. W przeciwnym razie jest to nieuczciwa funkcja i źródło błędów.
Nie zrozumcie mnie źle, że może istnieć kilka rodzin funkcji walczących o tę strukturę danych ze snitchem, płaszczem i podwójnym agentem wszędzie. To dobrze, gdy każdy z nich ma własną strukturę danych, z którą można się bawić, ale kiedy się nią dzielą ... wyobraź sobie, że kilka rodzin przestępczych nie zgadza się z polityką, może stać się naprawdę szybko bałaganem.
Biorąc pod uwagę bałagan, jaki rodziny rozszerzonych funkcji mogą osiągnąć, czy istnieje sposób na zakodowanie struktury danych, aby nieuczciwe funkcje nie zepsuły wszystkiego? Tak, nazywają się Obiektami.
Czy gettery / settery są przydatne w Objectach? Nie.
Cały sens zawijania struktury danych w obiekcie polegał na tym, aby nie istniały żadne nieuczciwe funkcje. Jeśli funkcja chciała dołączyć do rodziny, najpierw musiała zostać dokładnie sprawdzona, a następnie stać się częścią obiektu.
Punktem / celem gettera i setera jest umożliwienie funkcjom poza obiektem bezpośredniej zmiany układu pamięci obiektu. To brzmi jak otwarte drzwi dla łotrzyków ...
The Edge Case
Istnieją dwie sytuacje, w których publiczny getter / setter ma sens.
Kontenery i interfejsy kontenerów są idealnymi przykładami obu tych dwóch sytuacji. Kontener wewnętrznie zarządza strukturami danych (lista połączona, mapa, drzewo), ale zapewnia kontrolę nad określonym elementem wszystkim i różnym. Interfejs to streszcza i całkowicie ignoruje implementację i opisuje tylko oczekiwania.
Niestety wiele implementacji źle to rozumie i definiuje interfejs tego rodzaju obiektów, aby zapewnić bezpośredni dostęp do rzeczywistego obiektu. Coś jak:
To jest zepsute. Wdrożenia kontenera muszą jawnie przekazać kontrolę nad swoimi elementami wewnętrznymi komukolwiek, kto ich używa. Nie widziałem jeszcze języka o zmiennej wartości, w którym jest to w porządku (języki z semantyką wartości niezmiennej są z definicji w porządku z perspektywy niszczenia danych, ale niekoniecznie z perspektywy szpiegowania danych).
Możesz poprawić / poprawić gettery / setter, używając tylko semantyki kopiowania lub używając proxy:
Prawdopodobnie nieuczciwa funkcja mogłaby nadal odgrywać chaos (przy wystarczającym wysiłku większość rzeczy jest możliwa), ale semantyka kopiowania i / lub proxy zmniejsza prawdopodobieństwo wystąpienia wielu błędów.
Osoby pobierające / ustawiające prywatne
To ostatni bastion pobierających i ustawiających pracujących bezpośrednio na tym typie. W rzeczywistości nie nazwałbym nawet tych pobierających i ustawiających, ale akcesoria i manipulatory.
W tym kontekście czasami manipulowanie określoną częścią struktury danych zawsze / prawie zawsze / ogólnie wymaga określonego przechowywania ksiąg. Powiedzmy, że podczas aktualizacji katalogu głównego drzewa pamięć podręczna musi zostać wyczyszczona lub podczas uzyskiwania dostępu do zewnętrznego elementu danych należy uzyskać / zwolnić blokadę. W takich przypadkach sensowne jest zastosowanie zasady SUCHEJ i spakowanie tych działań razem.
W kontekście prywatnym nadal możliwe jest, aby inne funkcje w rodzinie pomijały te „moduły pobierające i ustawiające” oraz manipulowały strukturą danych. Dlatego myślę o nich bardziej jako o akcesoriach i manipulatorach. Możesz uzyskać bezpośredni dostęp do danych lub polegać na innym członku rodziny, aby uzyskać właściwą część.
Chronieni Getters / Setters
W kontekście chronionym nie różni się tak bardzo od kontekstu publicznego. Zagraniczne, prawdopodobnie nieuczciwe funkcje chcą dostępu do struktury danych. Więc nie, jeśli istnieją, działają jak publiczne podmioty pobierające / ustawiające.
źródło
Z doświadczenia w C ++ Setter / getter jest pomocny w 2 scenariuszach:
Oprócz tego bezpieczeństwo jest ważnym punktem, ale jego znaczenie jest ograniczone do bardzo niewielu aplikacji programistycznych, takich jak logowanie lub moduły związane z dostępem do bazy danych. Po co zawracać sobie głowę kodowaniem, skoro tylko kilka osób korzysta z tego modułu?
źródło