Dlaczego warto używać getterów i setterów / accessorów?

Jaka jest zaleta używania getterów i setterów-które tylko get I set - zamiast po prostu używać publicznych pól dla tych zmiennych?

Jeśli gettery i settery robią coś więcej niż tylko prosty get/set, mogę szybko to rozgryźć, ale nie jestem w 100% pewny jak:

public String foo;

Jest gorsze od:

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }
/ Align = "left" /
Author: Tim, 2009-10-14

30 answers

W rzeczywistości istnieje wiele dobrych powodów , aby rozważyć użycie accesorów zamiast bezpośrednio eksponować pola klasy - poza argumentem enkapsulacji i ułatwiania przyszłych zmian.

Oto niektóre z powodów, z których jestem świadomy:

  • enkapsulacja zachowania związanego z pobieraniem lub ustawianiem właściwości-pozwala to na łatwiejsze późniejsze dodanie dodatkowych funkcji (takich jak Walidacja).
  • ukrywanie wewnętrzna reprezentacja nieruchomości podczas wystawiania nieruchomości za pomocą alternatywnej reprezentacji.
  • izolowanie interfejsu publicznego od zmian-umożliwienie zachowania stałego interfejsu publicznego, podczas gdy implementacja zmienia się bez wpływu na istniejących konsumentów.
  • kontrolowanie semantyki życia i zarządzania pamięcią (utylizacja) właściwości - szczególnie ważne w nie zarządzanych środowiskach pamięci (takich jak C++ lub Objective-C).
  • zapewnienie debugowania punkt przechwytywania, gdy właściwość zmienia się w trybie runtime-debugowanie, kiedy i gdzie właściwość zmienia się na określoną wartość, może być dość trudne bez tego w niektórych językach.
  • Poprawiono interoperacyjność z bibliotekami zaprojektowanymi do działania przeciwko getterowi/seterom właściwości-przychodzą na myśl szyderstwa, serializacja i WPF.
  • Umożliwienie dziedzicom zmiany semantyki zachowania i ujawnienia właściwości poprzez nadpisanie gettera/settera metody.
  • pozwala na przekazywanie gettera/settera jako wyrażeń lambda, a nie wartości.
  • Gettery i settery mogą zezwalać na różne poziomy dostępu - na przykład get może być publiczny, ale zestaw może być chroniony.
 1046
Author: LBushkin,
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
2013-10-24 06:25:37

Ponieważ za 2 tygodnie (miesiące, lata), kiedy zdasz sobie sprawę, że Twój setter musi zrobić więcej niż tylko ustawić wartość, zdasz sobie również sprawę, że właściwość została użyta bezpośrednio w 238 innych klasach: -)

 512
Author: ChssPly76,
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
2009-10-14 18:23:19

Publiczne pole nie jest gorsze od pary getter / setter, która nie robi nic poza zwracaniem pola i przypisywaniem do niego. Po pierwsze, jest jasne, że (w większości języków) nie ma różnicy funkcjonalnej. Każda różnica musi wynikać z innych czynników, takich jak konserwacja lub czytelność.

Często wymienianą zaletą par getter/setter jest to, że można zmienić implementację i nie trzeba rekompilować klientów. Podobno setery pozwalają dodać funkcjonalność, taka jak Walidacja później, a twoi klienci nawet nie muszą o tym wiedzieć. Jednak dodanie walidacji do settera jest zmianą jego warunków wstępnych, naruszeniem poprzedniego kontraktu , które było po prostu "możesz umieścić wszystko tutaj, a to samo możesz uzyskać później od gettera".

Więc teraz, gdy zerwałeś umowę, zmienianie KAŻDEGO pliku w bazie kodowej jest czymś, co powinieneś zrobić, a nie unikać. Jeśli tego unikniesz, założysz że cały kod zakłada, że kontrakt na te metody jest inny.

Jeśli to nie była umowa, to interfejs pozwalał klientom umieścić obiekt w nieprawidłowych Stanach. to jest dokładne przeciwieństwo enkapsulacji Jeśli to pole nie mogło być ustawione na cokolwiek od początku, dlaczego Walidacja nie była tam od początku?

Ten sam argument odnosi się do innych rzekomych zalet tych przechodzących par getter / setter: jeśli później zdecyduj się na zmianę ustalanej wartości, zrywasz umowę. Jeśli nadpiszesz domyślną funkcjonalność w klasie pochodnej, w sposób wykraczający poza kilka nieszkodliwych modyfikacji (takich jak logowanie lub inne nieprzewidywalne zachowanie), łamiesz kontrakt klasy bazowej. Jest to naruszenie zasady substytucyjności Liskowa, która jest postrzegana jako jedna z zasad OO.

Jeśli klasa ma te głupie gettery i settery dla każdego pola, to jest to klasa, która nie ma niezmienników Brak umowy. Czy to naprawdę projekt zorientowany obiektowo? Jeśli klasa ma tylko te gettery i settery, jest to tylko głupi posiadacz danych, a głupi posiadacze danych powinni wyglądać jak głupi posiadacze danych: {]}

class Foo {
public:
    int DaysLeft;
    int ContestantNumber;
};

Dodanie pass-through Getter / setter do takiej klasy nie dodaje żadnej wartości. Inne klasy powinny zapewniać znaczące operacje, a nie tylko operacje, które pola już dostarczają. W ten sposób można definiować i utrzymywać użyteczne niezmienniki.

Client : "Co mogę zrobić z obiektem tej klasy?"
Designer: "możesz odczytywać i zapisywać kilka zmiennych."
Klient:.. fajnie, chyba?"

Istnieją powody, aby używać getterów i seterów, ale jeśli te powody nie istnieją, tworzenie par getter/setter w imię fałszywych bogów hermetyzacji nie jest dobrą rzeczą. Ważne powody, aby wprowadzić gettery lub settery, obejmują rzeczy często wymieniane jako potencjalne zmiany, które możesz wprowadzić później, takie jak Walidacja lub różne reprezentacje wewnętrzne. A może wartość powinna być czytelna dla klientów, ale nie do zapisania (na przykład czytanie rozmiaru słownika), więc prosty getter jest dobrym wyborem. Ale te powody powinny być tam, gdy dokonasz wyboru, a nie tylko jako potencjalna rzecz, którą możesz chcieć później. To jest przykład YAGNI (nie będziesz jej potrzebował).

 379
Author: R. Martinho Fernandes,
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-02-17 13:26:41

Wiele osób mówi o zaletach getterów i seterów, ale ja chcę grać adwokata diabła. W tej chwili debuguję bardzo duży program, w którym programiści postanowili zrobić wszystko, co getters i setters. To może wydawać się miłe, ale to koszmar inżynierii odwrotnej.

Powiedzmy, że przeglądasz setki linijek kodu i natkniesz się na to:

person.name = "Joe";

To piękny, prosty kawałek kodu, dopóki nie uświadomisz sobie, że jest to seter. Podążaj za seterem i znajdź, że to również ustawia osobę.imię, osoba.ostatnie imię, osoba.isHuman, osoba.ma reallycommonfirstname i wywołuje osobę.update (), która wysyła zapytanie do bazy danych, itd. To tam miał miejsce wyciek pamięci.

Zrozumienie lokalnego fragmentu kodu na pierwszy rzut oka jest ważną właściwością dobrej czytelności, którą getterzy i setterzy mają tendencję do łamania. Dlatego staram się ich unikać, Kiedy Mogę i minimalizować to, co robią, gdy ich używam.

 98
Author: Kai,
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
2009-10-14 21:00:47

W czystym obiektowo zorientowanym świecie getters i setters jest strasznym anty-wzorcem . Przeczytaj ten artykuł: Getters / Setters. Zło. Okres . W skrócie, zachęcają programistów do myślenia o obiektach jak o strukturach danych, a tego typu myślenie jest czysto proceduralne (jak w COBOLu czy C). W języku obiektowym nie ma struktur danych, a jedynie obiekty, które eksponują zachowanie (nie atrybuty/właściwości!)

Więcej o nich znajdziesz w punkcie 3.5 eleganckie Obiekty (moja książka o programowaniu obiektowym).

 59
Author: yegor256,
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
2019-08-21 07:01:40

Jest wiele powodów. Moim ulubionym jest, gdy trzeba zmienić zachowanie lub regulować, co można ustawić na zmiennej. Na przykład, powiedzmy, że masz metodę setSpeed(int speed). Ale chcesz, że można ustawić tylko maksymalną prędkość 100. Zrobiłbyś coś takiego:

public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}

A co jeśli wszędzie w kodzie używałeś pola publicznego, a potem zdałeś sobie sprawę, że potrzebujesz powyższego wymogu? Baw się dobrze polując na każde użycie publicznego pola zamiast tylko modyfikowanie setera.

Moje 2 grosze:)

 55
Author: Peter D,
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
2009-10-14 18:27:22

Jedną z zalet accessorów i mutatorów jest możliwość walidacji.

Na przykład, jeśli foo było publiczne, mogłem łatwo ustawić go na null i wtedy ktoś inny mógłby spróbować wywołać metodę na obiekcie. Ale już go tam nie ma! Dzięki metodzie setFoo mogłem upewnić się, że foo nigdy nie został ustawiony na null.

Accessory i mutatory pozwalają również na enkapsulację-jeśli nie powinieneś zobaczyć wartości po jej ustawieniu (być może jest ustawiona w konstruktorze, a następnie używana przez metody, ale nigdy nie powinny być zmieniane), to nigdy nie będzie postrzegane przez nikogo. Ale jeśli możesz pozwolić innym klasom zobaczyć lub zmienić to, możesz podać odpowiedni accessor i / lub mutator.

 40
Author: Thomas Owens,
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
2009-10-14 18:25:11

Zależy od Twojego języka. Otagowałeś to "zorientowane obiektowo", a nie" Java", więc chciałbym zwrócić uwagę, że odpowiedź ChssPly76 jest zależna od języka. Na przykład w Pythonie nie ma powodu, aby używać getterów i setterów. Jeśli chcesz zmienić zachowanie, możesz użyć właściwości, która otacza getter i setter wokół podstawowego dostępu do atrybutów. Coś takiego:

 class Simple(object):
   def _get_value(self):
       return self._value -1

   def _set_value(self, new_value):
       self._value = new_value + 1

   def _del_value(self):
       self.old_values.append(self._value)
       del self._value

   value = property(_get_value, _set_value, _del_value)
 29
Author: jcdyer,
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
2020-07-04 20:31:03

Chcę tylko dodać, że nawet jeśli czasami są one niezbędne do enkapsulacji i bezpieczeństwa Twoich zmiennych / obiektów, jeśli chcemy zakodować prawdziwy program obiektowy, to musimy przestań nadużywać akcesoriów, bo czasami wiele zależy od nich, gdy nie jest naprawdę konieczne i to sprawia, że prawie tak samo, jak gdybyśmy umieścić zmienne publiczne.

 26
Author: Jorge Aguilar,
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
2012-08-22 14:47:41

Dzięki, to naprawdę wyjaśniło moje myślenie. Oto (prawie) 10 (prawie) dobrych powodów, aby nie używać getterów i setterów:

  1. kiedy zdasz sobie sprawę, że musisz zrobić coś więcej niż tylko ustawić i uzyskać wartość, możesz po prostu uczynić pole prywatnym, które natychmiast powie Ci, gdzie masz bezpośredni dostęp do niego.
  2. każda Walidacja, którą tam wykonujesz, może być wolna od kontekstu, co rzadko zdarza się w praktyce.
  3. można zmienić ustawianą wartość - jest to absolutny koszmar, gdy dzwoniący przekazuje ci wartość, którą chcą, abyś przechowywał tak, jak jest.
  4. możesz ukryć wewnętrzną reprezentację-fantastycznie, więc upewniasz się, że wszystkie te operacje są symetryczne, prawda?
  5. odizolowałeś swój publiczny interfejs od zmian pod arkuszami - jeśli projektowałeś interfejs i nie byłeś pewien, czy bezpośredni dostęp do czegoś jest w porządku, powinieneś był dalej projektować.
  6. niektóre biblioteki spodziewaj się tego, ale nie wielu-odbicie, serializacja, obiekty makiety działają dobrze z polami publicznymi.
  7. dziedzicząc tę klasę, możesz nadpisać domyślną funkcjonalność - innymi słowy, możesz naprawdę mylić wywołujących, nie tylko ukrywając implementację, ale czyniąc ją niespójną.

Ostatnie trzy odchodzę (N/A lub D / C)...

 25
Author: StackedCrooked,
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
2012-08-23 21:25:59

Wiem, że jest trochę późno, ale myślę, że są ludzie, którzy są zainteresowani występem.

Zrobiłem mały test wydajności. Napisałem klasę "NumberHolder", która zawiera liczbę całkowitą. Możesz odczytać tę liczbę całkowitą za pomocą metody getter anInstance.getNumber() lub poprzez bezpośredni dostęp do numeru za pomocą anInstance.number. Mój program odczytuje liczbę 1,000,000,000 razy, w obie strony. Proces ten powtarza się pięć razy, a czas jest drukowany. Mam następujące wynik:
Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms

(Czas 1 jest bezpośrednią drogą, Czas 2 jest getterem)

Widzisz, getter jest (prawie) zawsze trochę szybszy. Potem próbowałem z różną liczbą cykli. Zamiast 1 miliona użyłem 10 milionów i 0,1 miliona. Wyniki:

10 milionów cykli:

Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms
Przy 10 milionach cykli czasy są prawie takie same. Oto 100 tysięcy (0,1 miliona) cykli:
Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms

Również z różną ilością cykli, getter jest trochę szybszy niż w zwykły sposób. Mam nadzieję, że ci to pomogło.

 23
Author: kangalioo,
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
2018-05-09 09:09:55

Nie używaj getters setters, chyba że są potrzebne do bieżącej dostawy tj. nie myśl zbyt wiele o tym, co stanie się w przyszłości, jeśli jakakolwiek rzecz, która ma zostać zmieniona, to żądanie zmiany w większości aplikacji produkcyjnych, systemów.

Myśl prosto, łatwo, dodaj złożoności w razie potrzeby.

Nie wykorzystałbym niewiedzy właścicieli firm o głębokiej wiedzy technicznej tylko dlatego, że uważam, że jest poprawne lub podoba mi się podejście.

Mam ogromny system napisany bez getters ustawia tylko modyfikatory dostępu i niektóre metody walidacji N wykonywania logiki biz. Jeśli absolutnie potrzebne. Użyj czegokolwiek.

 16
Author: Mohamed,
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
2012-07-14 16:20:27

Używamy getterów i setterów:

  • do wielokrotnego użytku
  • do wykonywania walidacji w późniejszych etapach programowania

Metody Getter i setter są publicznymi interfejsami umożliwiającymi dostęp do prywatnych członków klasy.


Mantra enkapsulacji

Mantra enkapsulacji polega na uczynieniu pól prywatnymi i metod publicznymi.

Metody gettera: możemy uzyskać dostęp do prywatnych zmiennych.

Setter Metody: możemy modyfikować pola prywatne.

Mimo że metody getter i setter nie dodają nowej funkcjonalności, możemy zmienić zdanie wrócić później, aby ta metoda

  • lepiej;
  • i
  • Szybciej.

Gdziekolwiek można użyć wartości, można dodać metodę, która zwraca tę wartość. Zamiast:

int x = 1000 - 500

Użycie

int x = 1000 - class_name.getValue();

U laika warunki

Reprezentacja klasy" Person"

Załóżmy, że musimy zapisać szczegóły tego Person. This Person has the fields name, age i sex. Polega to na stworzeniu metod dla name, age i sex. Teraz, jeśli potrzebujemy stworzyć inną osobę, konieczne staje się stworzenie metod dla name, age, sex / align = "left" /

Zamiast tego możemy stworzyć bean class(Person) za pomocą metod getter i setter. Więc jutro możemy po prostu tworzyć obiekty tej fasoli class(Person class) kiedy tylko trzeba dodać nową osobę(patrz rysunek). W ten sposób ponownie wykorzystujemy pola i metody klasy fasoli, co jest znacznie lepsze.

 16
Author: Devrath,
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
2013-12-19 05:22:04

EDIT: odpowiedziałem na to pytanie, ponieważ jest grupa ludzi uczących się programowania pytających o to, a większość odpowiedzi jest bardzo kompetentna technicznie, ale nie jest tak łatwa do zrozumienia, jeśli jesteś nowicjuszem. Wszyscy byliśmy nowicjuszami, więc pomyślałem, że spróbuję swoich sił w bardziej przyjaznej dla nowicjuszy odpowiedzi.

Dwa główne to polimorfizm i Walidacja. Nawet jeśli to tylko głupia struktura danych.

Powiedzmy, że mamy prostą klasę:

public class Bottle {
  public int amountOfWaterMl;
  public int capacityMl;
}

Bardzo prosta klasa to utrzymuje, ile jest w nim płynu i jaka jest jego pojemność (w mililitrach).

Co się dzieje, gdy robię:

Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacityMl = 1000;
Nie spodziewałbyś się, że to zadziała, prawda? Chcesz, żeby była jakaś kontrola zdrowia psychicznego. A co gorsza, co jeśli nigdy nie określiłem maksymalnej pojemności? Ojej, mamy problem. Ale jest też inny problem. A gdyby butelki były tylko jednym rodzajem pojemnika? Co by było, gdybyśmy mieli kilka pojemników, wszystkie z pojemnościami i ilością wypełnionych płynów? Jeśli my moglibyśmy po prostu stworzyć interfejs, moglibyśmy pozwolić reszcie naszego programu zaakceptować ten interfejs, a butelki, kanistry i wszelkiego rodzaju rzeczy po prostu działały zamiennie. Nie byłoby lepiej? Ponieważ interfejsy wymagają metod, jest to również dobra rzecz.

Skończylibyśmy z czymś takim:

public interface LiquidContainer {
  public int getAmountMl();
  public void setAmountMl(int amountMl);
  public int getCapacityMl();
}
Świetnie! A teraz zmieniamy butelkę na to:
public class Bottle extends LiquidContainer {
  private int capacityMl;
  private int amountFilledMl;

  public Bottle(int capacityMl, int amountFilledMl) {
    this.capacityMl = capacityMl;
    this.amountFilledMl = amountFilledMl;
    checkNotOverFlow();
  }

  public int getAmountMl() {
    return amountFilledMl;
  }

  public void setAmountMl(int amountMl) {
     this.amountFilled = amountMl;
     checkNotOverFlow();
  }
  public int getCapacityMl() {
    return capacityMl;
  }

  private void checkNotOverFlow() {
    if(amountOfWaterMl > capacityMl) {
      throw new BottleOverflowException();
    }
}

Zostawię definicję BottleOverflowException jako ćwiczenie dla czytelnika.

Teraz zauważ ile to jest bardziej wytrzymałe. Możemy poradzić sobie z każdym rodzajem pojemnika w naszym kodzie, akceptując LiquidContainer zamiast butelki. A to, jak te butelki radzą sobie z tego rodzaju rzeczami, może się różnić. Możesz mieć butelki, które zapisują swój stan na dysku, gdy się zmieni, lub butelki, które zapisują w bazach danych SQL lub GNU wie co jeszcze.

/ Align = "left" / Butelka tylko sprawdza, a jeśli jest przepełniona, rzuca RuntimeException. Ale to może być źle postąpiłem. (Istnieje przydatna dyskusja na temat obsługi błędów, ale celowo utrzymuję to bardzo proste. Ludzie w komentarzach prawdopodobnie wskażą wady tego uproszczonego podejścia. ;) )

I tak, wydaje się, że przechodzimy od bardzo prostego pomysłu do uzyskania znacznie lepszych odpowiedzi szybko.

Należy również pamiętać, że nie można zmienić pojemności butelki. Teraz jest w kamieniu. Możesz to zrobić za pomocą int, ogłaszając to ostatecznym. Ale jeśli to była lista, może go opróżnić, dodać do niego nowe rzeczy i tak dalej. Nie możesz ograniczać dostępu do dotykania wnętrzności.

Jest też trzecia rzecz, o której nie wszyscy mówili: gettery i settery używają wywołań metod. Oznacza to, że wyglądają jak normalne metody wszędzie indziej. Zamiast mieć dziwną specyficzną składnię DTOs i takie tam, wszędzie masz to samo.

 16
Author: Haakon Løtveit,
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
2019-06-14 13:07:22

Spędziłem trochę czasu na rozmyślaniu nad tym dla sprawy Javy i wierzę, że prawdziwe powody są następujące:

  1. kod do interfejsu, a nie implementacji
  2. interfejsy określają tylko metody, a nie Pola

Innymi słowy, jedynym sposobem na określenie pola w interfejsie jest podanie metody zapisu nowej wartości i metody odczytu bieżącej wartości.

Te metody to niesławny getter i setter....

 15
Author: Thorbjørn Ravn Andersen,
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
2009-11-07 21:55:17

Może być przydatny do leniwego ładowania. Powiedzmy, że dany obiekt jest przechowywany w bazie danych i nie chcesz go zdobyć, chyba że go potrzebujesz. Jeśli obiekt jest pobierany przez getter, wtedy wewnętrzny obiekt może być null, dopóki ktoś o niego nie poprosi, wtedy możesz go pobrać przy pierwszym wywołaniu gettera.

Miałem podstawową klasę strony w projekcie, który został mi przekazany, który ładował dane z kilku różnych wywołań usług internetowych, ale dane w tych połączeniach nie były zawsze używany we wszystkich stronach potomnych. Usługi internetowe, dla wszystkich korzyści, pioneer nowe definicje "powolny", więc nie chcesz, aby połączenie usługi internetowej, jeśli nie trzeba.

Przeniosłem się z publicznych pól do getterów, a teraz getterzy sprawdzają pamięć podręczną, a jeśli jej nie ma, dzwonią do serwisu internetowego. Więc przy odrobinie zawijania, wiele połączeń z serwisami internetowymi zostało zablokowanych.

Więc getter ratuje mnie przed próbami rozgryzienia, na każdej stronie dziecka, czego będę potrzebował. Jeśli będę tego potrzebował, zadzwonię. getter, i idzie go znaleźć dla mnie, jeśli jeszcze go nie mam.

    protected YourType _yourName = null;
    public YourType YourName{
      get
      {
        if (_yourName == null)
        {
          _yourName = new YourType();
          return _yourName;
        }
      }
    }
 15
Author: quillbreaker,
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-09-19 18:20:55

Jeden aspekt brakowało mi w odpowiedziach do tej pory, Specyfikacja dostępu:

  • dla członków masz tylko jedną specyfikację dostępu dla ustawienia i uzyskania
  • dla seterów i getterów możesz go dostroić i zdefiniować osobno
 13
Author: jdehaan,
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
2009-10-14 18:38:28

W językach, które nie obsługują "właściwości" (C++, Java) lub wymagają rekompilacji klientów przy zmianie pól na właściwości( C#), używanie metod get/set jest łatwiejsze do modyfikacji. Na przykład, dodanie logiki walidacji do metody setFoo nie będzie wymagało zmiany publicznego interfejsu klasy.

W językach, które obsługują "prawdziwe" właściwości (Python, Ruby, może Smalltalk?) nie ma sensu pobierać/ustawiać metod.

 10
Author: John Millikin,
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
2009-10-14 19:13:42

Jedna z podstawowych zasad projektowania OO: enkapsulacja!

Daje wiele korzyści, z których jedną jest możliwość zmiany implementacji gettera / settera za kulisami, ale każdy konsument o tej wartości będzie działał tak długo, jak typ danych pozostanie taki sam.

 6
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
2009-10-14 18:25:19

Powinieneś używać getterów i setterów, gdy:

  • masz do czynienia z czymś, co jest koncepcyjnie atrybutem, ale:
    • twój język nie ma właściwości (lub podobnego mechanizmu, takiego jak zmienne ślady TCL), lub
    • Wsparcie właściwości Twojego języka nie jest wystarczające dla tego przypadku użycia, lub
    • idiomatyczne konwencje Twojego języka (lub czasami twojego frameworka) zachęcają gettery lub settery do tego zastosowania.

Więc to jest bardzo rzadko pytanie ogólne OO; jest to pytanie specyficzne dla danego języka, z różnymi odpowiedziami dla różnych języków (i różnymi przypadkami użycia).


Z punktu widzenia teorii OO, gettery i settery są bezużyteczne. Interfejs twojej klasy jest tym, co robi, a nie jaki jest jego stan. (Jeśli nie, napisałeś złą klasę.) W bardzo prostych przypadkach, gdzie to, co robi klasa, jest po prostu, np. reprezentuje punkt we współrzędnych prostokątnych,* atrybuty są częścią interfejsu; getters a setery tylko to zaciemniają. Ale w bardzo prostych przypadkach ani atrybuty, ani gettery i settery nie są częścią interfejsu.

Ująć inaczej: jeśli uważasz, że konsumenci twojej klasy nie powinni nawet wiedzieć, że masz atrybut spam, a tym bardziej nie być w stanie go zmienić, to podanie im metody set_spam jest ostatnią rzeczą, którą chcesz zrobić.

* nawet dla tej prostej klasy, niekoniecznie musisz pozwolić na ustawienie wartości x i y. Jeśli to naprawdę Klasa, to czy nie powinna mieć takich metod jak translate, rotate, itd.? Jeśli jest to tylko Klasa, ponieważ twój język nie ma rekordów/struktur / nazwanych krotek, to tak naprawdę nie jest to kwestia OO ...


/ Align = "left" / Projektują i realizują w określonym języku. A w niektórych językach, gettery i settery są dalekie od bezużytecznych.

Jeśli twój język nie ma właściwości, to jedynym sposobem na reprezentowanie czegoś to jest koncepcyjnie atrybut, ale jest faktycznie obliczony, lub zatwierdzony, itp., jest przez getterów i seterów.

Nawet jeśli twój język ma właściwości, mogą się zdarzyć przypadki, gdy są one niewystarczające lub nieodpowiednie. Na przykład, jeśli chcesz zezwolić podklasom na kontrolowanie semantyki atrybutu, w językach bez dostępu dynamicznego, podklasa nie może zastąpić właściwości obliczeniowej atrybutem.

Jeśli chodzi o " co zrobić, jeśli chcę zmienić moją implementację później?" pytanie (które jest powtarzane wielokrotnie w różnych sformułowaniach zarówno w pytaniu OP, jak i w zaakceptowanej odpowiedzi): jeśli jest to naprawdę czysta zmiana implementacji, a zacząłeś od atrybutu, możesz zmienić go na właściwość bez wpływu na interfejs. Chyba, że twój język tego nie wspiera. Więc to znowu ta sama sprawa.

Ważne jest również, aby postępować zgodnie z idiomami używanego języka (lub frameworka). Jeśli napiszesz piękny Kod W Stylu Ruby w C# każdy doświadczony programista C# inny niż ty będzie miał problemy z jego odczytaniem, a to jest złe. Niektóre języki mają silniejsze Kultury wokół swoich konwencji niż inne.- i nie może być przypadkiem, że Java i Python, które są na przeciwnych końcach spektrum dla tego, jak idiomatyczne gettery są, mają dwie najsilniejsze Kultury.

Poza ludzkimi czytelnikami, będą biblioteki i narzędzia, które oczekują od Ciebie przestrzegania konwencji i utrudniają Ci życie, jeśli Nie. Podłączanie widżetów Interface Builder do czegokolwiek poza właściwościami ObjC, lub używanie niektórych bibliotek Java wyśmiewanie bez getterów, po prostu utrudnia Ci życie. Jeśli narzędzia są dla Ciebie ważne, nie walcz z nimi.

 5
Author: abarnert,
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 04:47:03

Z punktu widzenia projektowania orientacji obiektowej obie alternatywy mogą być szkodliwe dla zachowania kodu, osłabiając enkapsulację klas. Do dyskusji Możesz zajrzeć do tego wspaniałego artykułu: http://typicalprogrammer.com/?p=23

 4
Author: andrers52,
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
2012-04-30 19:08:29

Metody Getter i setter są metodami dostępowymi, co oznacza, że są ogólnie publicznym interfejsem do zmiany prywatnych członków klasy. Do definiowania właściwości używa się metod getter i setter. Uzyskujesz dostęp do metod getter i setter jako właściwości poza klasą, nawet jeśli definiujesz je wewnątrz klasy jako metody. Te właściwości poza klasą mogą mieć inną nazwę niż nazwa właściwości w klasie.

Istnieją pewne zalety stosowania metod getter i setter, takich jak jako możliwość tworzenia członków o wyrafinowanej funkcjonalności, do których można uzyskać dostęp jak właściwości. Umożliwiają również tworzenie właściwości tylko do odczytu i tylko do zapisu.

Mimo że metody getter i setter są przydatne, Należy uważać, aby nie nadużywać ich, ponieważ, między innymi, mogą one utrudnić konserwację kodu w pewnych sytuacjach. Zapewniają również dostęp do implementacji klasy, Jak członkowie publiczni. Praktyka OOP zniechęca do bezpośredniego dostępu do właściwości w ramach klasy.

Kiedy piszesz klasy, zawsze jesteś zachęcany, aby jak najwięcej zmiennych instancji było prywatnych i odpowiednio dodawać metody getter i setter. Dzieje się tak dlatego, że kilka razy możesz nie chcieć pozwolić użytkownikom na zmianę pewnych zmiennych w Twoich klasach. Na przykład, jeśli masz prywatną statyczną metodę, która śledzi liczbę instancji utworzonych dla określonej klasy, nie chcesz, aby użytkownik modyfikował ten licznik za pomocą kodu. Tylko Instrukcja constructor powinna zwiększyć tę zmienną za każdym razem, gdy jest wywołana. W tej sytuacji można utworzyć zmienną wystąpienia prywatnego i zezwolić na metodę getter tylko dla zmiennej counter, co oznacza, że użytkownicy mogą pobrać bieżącą wartość tylko za pomocą metody getter i nie będą mogli ustawić nowych wartości za pomocą metody setter. Tworzenie gettera bez settera jest prostym sposobem tworzenia pewnych zmiennych w klasie tylko do odczytu.

 3
Author: Sumit Singh,
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
2012-08-30 13:02:26

Kod ewoluuje. {[3] } jest świetny do kiedy potrzebujesz ochrony danych . Ostatecznie wszystkie klasy powinny być rodzajem "miniprogramów", które mają dobrze zdefiniowany interfejs , którego nie można po prostu wkręcić z wewnętrznymi.

To powiedziawszy, tworzenie oprogramowania nie polega na ustawianiu ostatecznej wersji klasy tak, jakbyś naciskał jakiś żeliwny posąg za pierwszym razem. Podczas pracy z nim, kod jest bardziej jak clay. It ewoluuje w miarę rozwoju i dowiadywania się więcej o dziedzinie problemu, którą rozwiązujesz. Podczas programowania klasy mogą wchodzić ze sobą w interakcje niż powinny (zależność, którą planujesz uwzględnić), łączyć się ze sobą lub rozdzielać. Więc myślę, że debata sprowadza się do ludzi, którzy nie chcą religijnie pisać

int getVar() const { return var ; }

Więc masz:

doSomething( obj->getVar() ) ;

Zamiast

doSomething( obj->var ) ;

Nie tylko jest getVar() wizualnie hałaśliwy, ale daje złudzenie, że gettingVar() jest w jakiś sposób bardziej złożonym procesem niż jest naprawdę. To, w jaki sposób Ty (jako autor klasowy) postrzegasz świętość var jest szczególnie mylące dla użytkownika twojej klasy, jeśli ma on Ustawiacz passthru -- wtedy wygląda na to, że stawiasz te bramy, aby "chronić" coś, co twierdzisz, że jest cenne, (świętość var) ale nawet ty przyznajesz, że ochrona var nie jest wiele warta przez zdolność każdego do wchodzenia i wchodzenia.set var do wartości, jakiej chcą, bez podglądania na to, co robią.

Więc Ja program w następujący sposób (zakładając podejście typu "zwinnego" -- czyli kiedy piszę kod nie wiedząc dokładnie co będzie robił/nie mam czasu ani doświadczenia, aby zaplanować rozbudowany zestaw interfejsu stylu wodospadu):

1) Zacznij od wszystkich członków publicznych dla podstawowych obiektów z danymi i zachowaniem. Dlatego w całym moim "przykładowym" kodzie C++ zauważysz, że wszędzie używam struct zamiast class.

2) gdy wewnętrzne zachowanie obiektu dla elementu danych staje się wystarczająco złożone, (na przykład, lubi utrzymywać wewnętrzny std::list w jakiejś kolejności), funkcje typu accessor są zapisywane. Ponieważ programuję sam, nie zawsze ustawiam członka private od razu, ale gdzieś w dół ewolucji klasy członek będzie "promowany" albo protected albo private.

3) klasy, które są w pełni dopracowane i mają ścisłe zasady dotyczące ich wewnętrznych (tzn. oni wiedzą dokładnie, co robią, a ty nie masz "pieprzyć" (termin techniczny) z jego wewnętrzne) otrzymują oznaczenie class, domyślnych członków prywatnych, a tylko kilku wybranych członków może być public.

Uważam, że takie podejście pozwala mi uniknąć siedzenia i religijnego pisania getter / setters, gdy wiele członków danych zostanie migrowanych, przesuniętych wokół itp. we wczesnych stadiach ewolucji klasy.

 3
Author: bobobobo,
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
2013-05-05 02:13:09

Istnieje dobry powód, aby rozważyć użycie accessors jest nie ma dziedziczenia własności. Zobacz następny przykład:

public class TestPropertyOverride {
    public static class A {
        public int i = 0;

        public void add() {
            i++;
        }

        public int getI() {
            return i;
        }
    }

    public static class B extends A {
        public int i = 2;

        @Override
        public void add() {
            i = i + 2;
        }

        @Override
        public int getI() {
            return i;
        }
    }

    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.i);
        a.add();
        System.out.println(a.i);
        System.out.println(a.getI());
    }
}

Wyjście:

0
0
4
 3
Author: GeZo,
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-05-13 09:47:35

Gettery i settery są używane do implementacji dwóch podstawowych aspektów programowania obiektowego, które są:

  1. abstrakcja
  2. enkapsulacja

Załóżmy, że mamy klasę pracownika:

package com.highmark.productConfig.types;

public class Employee {

    private String firstName;
    private String middleName;
    private String lastName;

    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
         this.middleName = middleName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName(){
        return this.getFirstName() + this.getMiddleName() +  this.getLastName();
    }
 }

Tutaj szczegóły implementacji pełnej nazwy są ukryte przed użytkownikiem i nie są dostępne bezpośrednio dla użytkownika, w przeciwieństwie do atrybutu publicznego.

 3
Author: Pritam Banerjee,
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
2016-07-05 22:32:35

Innym zastosowaniem (w językach, które obsługują właściwości) jest to, że settery i gettery mogą sugerować, że operacja jest nietrywialna. Zazwyczaj chcesz uniknąć robienia czegokolwiek, co jest kosztowne obliczeniowo w nieruchomości.

 2
Author: Jason Baker,
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
2009-10-14 18:27:45

Jedną ze stosunkowo nowoczesnych zalet getterów / setterów jest to, że ułatwia przeglądanie kodu w edytorach oznaczonych (indeksowanych). Na przykład, jeśli chcesz zobaczyć, kto ustawia członka, możesz otworzyć hierarchię wywołań settera.

Z drugiej strony, jeśli członek jest publiczny, narzędzia nie umożliwiają filtrowania dostępu do odczytu/zapisu do członka. Więc musisz przeforsować wszystkie zastosowania członka.

 2
Author: Rakesh Singh,
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-01-03 16:10:02

W języku obiektowym metody i ich modyfikatory dostępu deklarują interfejs dla tego obiektu. Pomiędzy konstruktorem a metodami accessor i mutator możliwe jest, aby programista kontrolował dostęp do wewnętrznego stanu obiektu. Jeśli zmienne są po prostu zadeklarowane jako publiczne, to nie ma możliwości regulacji tego dostępu. A kiedy używamy setterów, możemy ograniczyć użytkownika do danych wejściowych, których potrzebujemy. Oznacza, że kanał dla tej bardzo zmiennej przejdzie przez właściwe kanał i kanał jest predefiniowany przez nas. Więc bezpieczniej jest używać seterów.

 2
Author: Antz,
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-11-04 17:11:33

DODATKOWO, jest to "przyszłościowe" klasy. W szczególności, zmiana z pola na właściwość jest łamaniem ABI, więc jeśli później zdecydujesz, że potrzebujesz więcej logiki niż tylko "set/get the field", musisz łamać ABI, co oczywiście stwarza problemy dla czegokolwiek innego już skompilowanego przeciwko twojej klasie.

 1
Author: Pete,
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
2009-10-14 18:25:59

Chciałbym tylko rzucić pomysł adnotacji: @ getter i @setter. Z @getter, powinieneś być w stanie obj = class.pole, ale nie klasa.pole = obj. Z @setter, vice versa. Z @getter i @setter powinieneś być w stanie zrobić oba. Zachowałoby to enkapsulację i skróciłoby czas, nie wywołując trywialnych metod w czasie wykonywania.

 1
Author: fastcodejava,
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
2009-10-14 22:40:24