Czytałem tę stronę o tym , kiedy getters / setters są uzasadnieni, a OP podał następujący przykładowy kod:
class Fridge
{
int cheese;
void set_cheese(int _cheese) { cheese = _cheese; }
int get_cheese() { return cheese; }
}
void go_shopping(Fridge fridge)
{
fridge.set_cheese(fridge.get_cheese() + 5);
}
W Zaakceptowanych odpowiedź stany:
Nawiasem mówiąc, w swoim przykładzie, dałbym klasę i metod, zamiast i . Wtedy nadal miałbyś enkapsulację.
Fridge
putCheese()
takeCheese()
get_cheese()
set_cheese()
Jak zachowuje się enkapsulację, zmieniając jej nazwę z get / set na putCheese()
/ takeCheese()
Oczywiście otrzymujesz / ustawiasz wartość, więc dlaczego nie po prostu zostawić ją jako get / set?
W tej samej odpowiedzi stwierdza również:
Posiadanie getterów i seterów samo w sobie nie przerywa enkapsulacji. To, co przerywa enkapsulację, to automatyczne dodawanie gettera i settera dla każdego członka danych (każdego pola, w języku Java), bez zastanowienia.
W tym przypadku mamy tylko jedną zmienną, cheese
i możesz chcieć wziąć i zwrócić ser do lodówki, więc w takim przypadku para get / set jest uzasadniona.
źródło
putCheese
dodaje ser do lodówki itakeCheese
usuwa go - są to abstrakcje zorientowane na domenę (wyższy poziom), a nie obiekty pobierające i ustawiające pola obiektowe (które są (niskopoziomowymi) abstrakcjami programowania komputerowego).Odpowiedzi:
Myślę, że nie rozumiesz sedna sprawy. To nie znaczy, że powinieneś zmienić nazwę setera i gettera, ale mieć metody, które dodają i usuwają przedmioty z lodówki. to znaczy
Teraz zmienna prywatna jest enkapsulowana. Nie mogę po prostu ustawić tego, co chcę, mogę tylko dodawać i usuwać plastry sera z lodówki za pomocą metod, które z kolei zapewniają, że zastosowane zostaną wszelkie zasady logiki biznesowej dotyczące sera.
źródło
setCheese()
ma on taką samą logikę w ustawieniach. Dla mnie i tak próbujesz ukryć fakt, że używasz setera, zmieniając nazwę metody, ale oczywiście twój getter / ustawienie czegoś.AddCheese(Integer.MAX_VALUE)
powinno zawieść, ale nie.Gettery i settery przerywają enkapsulację za każdym razem , z definicji. Co może argumentować, że czasami musimy zrobić. W tym miejscu są moje odpowiedzi:
Różnica polega na semantyce, czyli na znaczeniu tego, co piszesz. W enkapsulacji chodzi nie tylko o ochronę, ale o ukrywanie stanu wewnętrznego. Stan wewnętrzny nie powinien być nawet znany na zewnątrz, zamiast tego obiekt powinien oferować metody biznesowe (czasami określane jako „zachowanie”) do manipulowania / używania tego stanu.
Tak
get
iset
są terminy techniczne i wydają się mieć nic wspólnego z „lodówką” domeny, podczasput
itake
może faktycznie jakiś sens.Jednak , czy
put
lubtake
uczynić rzeczywisty sens nadal zależy od wymagań i nie mogą być obiektywnie ocenione. Zobacz następny punkt:Nie można tego obiektywnie ustalić bez większego kontekstu. Twój przykład zawiera
go_shopping()
metodę gdzie indziej. Jeśli po toFridge
jest, to nie potrzebujeget
lubset
to, czego potrzebujeFridge.go_shopping()
. W ten sposób masz metodę wyprowadzoną z wymagań, wszystkie „dane”, których potrzebuje, są lokalne i masz rzeczywiste zachowanie zamiast tylko cienko zawoalowanej struktury danych.Pamiętaj, że nie budujesz ogólnego, wielokrotnego użytku
Fridge
. Budujesz tylkoFridge
dla swoich wymagań. Wszelkie wysiłki włożone w zarabianie na tym, co trzeba, są w rzeczywistości marnotrawstwem.źródło
Getters and setters break encapsulation every single time
- To trochę zbyt mocno sformułowane na mój gust. Metody (w tym gettery i setery) mają ten sam cel, co bramki na koncercie: umożliwiają uporządkowane wejście i wyjście z miejsca.public int getFoo()
go masz, praktycznie niemożliwe jest przejście na inny typ.Prawie wszystko to pokazuje fundamentalne nieporozumienie dotyczące enkapsulacji i jej zastosowania.
Początkowa odpowiedź, że łamałeś enkapsulację, jest po prostu zła. Twoja aplikacja może wymagać jedynie ustawienia wartości sera w lodówce zamiast zwiększania / zmniejszania lub dodawania / usuwania. Ponadto nie jest to semantyka, bez względu na to, jak ją nazwiesz, jeśli musisz uzyskać dostęp i / lub zmienić atrybuty, nie przerywasz enkapsulacji, zapewniając je. Wreszcie, enkapsulacja tak naprawdę nie polega na „ukrywaniu się”, ale na kontrolowaniu dostępu do stanu i wartości, które nie powinny być publiczne ani manipulowane poza klasą, przy jednoczesnym przyznaniu go tym, którzy powinni, i wykonaniu zadania udostępnionego wewnętrznie.
Narzędzie pobierające lub ustawiające nie przerywa enkapsulacji, gdy istnieje uzasadniona potrzeba uzyskania lub ustawienia wartości. Właśnie dlatego metody można upublicznić.
Hermetyzacja polega na przechowywaniu danych i metodach, które modyfikują te dane bezpośrednio razem w jednym logicznym miejscu, klasie.
W tym szczególnym przypadku istnieje wyraźna potrzeba zmiany wartości sera we wniosku. Niezależnie od tego, jak to się robi, poprzez get / set lub add / remove, o ile metody są zawarte w klasie, postępujesz zgodnie ze stylem obiektowym.
Dla wyjaśnienia podam przykład złamania enkapsulacji poprzez zapewnienie dostępu bez względu na nazwę metody lub logiczne wykonanie.
Powiedzmy, że lodówka ma „żywotność”, wystarczy kilka tyknięć, zanim lodówka przestanie działać (ze względu na argument, lodówki nie można naprawić). Logicznie rzecz biorąc, nie ma możliwości, aby użytkownik (lub reszta aplikacji) mógł zmienić tę wartość. To powinno być prywatne. Byłoby to widoczne tylko poprzez powiedzenie innego publicznego atrybutu znanego jako „isWorking”. Po upływie okresu żywotności, wewnętrzne zestawy lodówek działają na fałsz.
Odliczanie czasu życia i przestawianie przełącznika isWorking jest wewnętrzne dla lodówki, nic na zewnątrz nie może / powinno mieć wpływu na proces. isWorking powinien być widoczny tylko dlatego getter nie przerywa enkapsulacji. Jednak dodanie akcesoriów dla elementów całego cyklu życia spowodowałoby uszkodzenie enkapsulacji.
Jak większość rzeczy, definicja enkapsulacji nie jest dosłowna, jest względna. Czy powinieneś widzieć X poza klasą? Czy powinieneś być w stanie zmienić Y? Czy wszystko, co dotyczy twojego obiektu tutaj w tej klasie, czy też funkcjonalność jest rozłożona na wiele klas?
źródło
To nie tylko zmiana nazwy metody. Te dwie metody działają inaczej.
(Wyobraź to sobie w pamięci)
get_cheese i set_cheese eksponują ser. putCheese () i takeCheese () ukrywają ser, dbają o zarządzanie nim i dają użytkownikowi sposób na jego obsługę. Obserwator nie widzi sera, widzi tylko dwie metody manipulowania nim.
źródło