W jaki sposób można uzyskać dostęp do właściwości obiektu z poziomu metody obiektu? [Zamknięte]

96

Jaki jest „purystyczny” lub „poprawny” sposób uzyskiwania dostępu do właściwości obiektu z poziomu metody obiektu, która nie jest metodą pobierającą / ustawiającą?

Wiem, że spoza obiektu powinieneś użyć metody pobierającej / ustawiającej, ale od wewnątrz po prostu zrobiłbyś:

Jawa:

String property = this.property;

PHP:

$property = $this->property;

czy zrobiłbyś:

Jawa:

String property = this.getProperty();

PHP:

$property = $this->getProperty();

Wybacz mi, jeśli moja Java jest trochę zepsuta, minął rok odkąd programowałem w Javie ...

EDYTOWAĆ:

Wygląda na to, że ludzie zakładają, że mówię tylko o prywatnych lub chronionych zmiennych / właściwościach. Kiedy nauczyłem się OO, nauczono mnie, jak używać pobierających / ustawiających wartości dla każdej właściwości, nawet jeśli byłaby ona publiczna (a właściwie powiedziano mi, żebym nigdy nie upubliczniał żadnej zmiennej / właściwości). Więc od samego początku mogę zacząć od fałszywego założenia. Wygląda na to, że ludzie odpowiadający na to pytanie mogą twierdzić, że powinieneś mieć własności publiczne i że nie potrzebują one getterów i seterów, co jest sprzeczne z tym, czego mnie uczono i o czym mówiłem, chociaż może należy to omówić jako dobrze. To chyba dobry temat na inne pytanie ...

cmcculloh
źródło

Odpowiedzi:

62

Ma to religijny potencjał wojenny, ale wydaje mi się, że jeśli używasz gettera / settera, powinieneś używać go również wewnętrznie - użycie obu doprowadzi do problemów z konserwacją w przyszłości (np. Ktoś dodaje kod do ustawiacza, który potrzebuje do uruchamiania za każdym razem, gdy ta właściwość jest ustawiana, a właściwość jest ustawiana wewnętrznie bez wywołania tej metody ustawiającej).

Greg Hurlman
źródło
nie robi nic innego w setterze poza ustawieniem wartości właściwości, co jest przykładem złego użycia w Javie.
euphoria83
1
@ euphoria83 Być może, ale to nie wyklucza tego.
Greg Hurlman
Zgadzam się z pierwotną odpowiedzią. Jednak pamiętaj tylko, że jeśli ustawiasz lub uzyskujesz coś prywatnego w klasie lub obiekcie, musisz upewnić się, że metoda pobierająca / ustawiająca nie jest cykliczna lub redundantna w sposób, który powoduje awarię kodu. Jeśli nie możesz użyć metody pobierającej / ustawiającej, uzyskaj do niej bezpośredni dostęp. (Np. Twój getter / setter uzyskuje dostęp do dodatkowej (prywatnej / chronionej) metody manipulowania danymi.)
Rick Mac Gillis
43

Osobiście uważam, że ważne jest, aby zachować konsekwencję. Jeśli masz metody pobierające i ustawiające, użyj ich. Jedyny przypadek, w którym miałbym bezpośredni dostęp do pola, to sytuacja, w której akcesor ma dużo narzutu. Może się wydawać, że niepotrzebnie nadymasz swój kod, ale z pewnością może to zaoszczędzić wiele bólu głowy w przyszłości. Klasyczny przykład:

Później możesz chcieć zmienić sposób działania tego pola. Może powinien być obliczany w locie, a może chciałbyś użyć innego typu dla magazynu zapasowego. Jeśli uzyskujesz dostęp do właściwości bezpośrednio, taka zmiana może zepsuć ogromną ilość kodu w jednym, zwiększonym stopniu.

MojoFilter
źródło
26

Jestem dość zaskoczony, jak jednomyślny jest ten sentyment, gettersa setery są w porządku i dobre. Proponuję artykuł zapalający Allena Holuba „ Getters And Setters Are Evil ”. To prawda, tytuł ma wartość szokującą, ale autor podaje ważne punkty.

Zasadniczo, jeśli masz gettersi settersdla każdego pola prywatnego, sprawiasz, że te pola są równie dobre, jak publiczne. Byłoby bardzo trudno zmienić typ prywatnego pola bez efektów falowania dla każdej klasy, która to wywołuje getter.

Ponadto, z punktu widzenia ściśle OO, obiekty powinny odpowiadać na wiadomości (metody), które odpowiadają ich (miejmy nadzieję) pojedynczej odpowiedzialności. Zdecydowana większość obiektów składowych gettersi settersnie ma dla nich sensu; Pen.dispenseInkOnto(Surface)ma dla mnie więcej sensu niż Pen.getColor().

Metody pobierające i ustawiające zachęcają również użytkowników klasy do żądania od obiektu pewnych danych, wykonywania obliczeń, a następnie ustawiania innej wartości w obiekcie, lepiej znanej jako programowanie proceduralne. Lepiej byłoby po prostu powiedzieć obiektowi, aby zrobił to, co zamierzałeś zrobić; znany również jako idiom Information Expert .

Jednak metody pobierające i ustawiające to zło konieczne na granicy warstw - interfejs użytkownika, wytrwałość i tak dalej. Ograniczony dostęp do elementów wewnętrznych klasy, takich jak słowo kluczowe friend w C ++, dostęp chroniony pakietem Javy, dostęp wewnętrzny .NET i wzorzec klasy znajomego może pomóc w ograniczeniu widoczności gettersi ustawieniach tylko do tych, którzy ich potrzebują.

moffdub
źródło
19

To zależy od sposobu użytkowania nieruchomości. Załóżmy na przykład, że masz obiekt studenta, który ma właściwość name. Możesz użyć metody Get, aby pobrać nazwę z bazy danych, jeśli nie została jeszcze pobrana. W ten sposób redukujesz niepotrzebne wywołania bazy danych.

Teraz powiedzmy, że masz prywatny licznik liczb całkowitych w swoim obiekcie, który zlicza, ile razy nazwa została wywołana. Możesz chcieć nie używać metody Get z wnętrza obiektu, ponieważ spowodowałoby to niepoprawną liczbę.

Shawn
źródło
Jeśli obiekt Studenta jest obiektem biznesowym / domenowym, mieszasz teraz szczegóły infrastruktury. W idealnym przypadku obiekty biznesowe / domeny powinny zajmować się tylko logiką biznesową / domenową.
moffdub,
Co się stanie, jeśli dodasz do metody pobierającej jakieś wartości logiczne, takie jak: PHP: public function getName ($ outsideCall = true) {if ($ outsideCall) {$ this-> IncrementNameCalled (); } return $ this-> name; } a następnie z samego obiektu, jeśli wywołałeś get name, możesz zapobiec zwiększaniu jego wartości przez: PHP: $ name = $ this-> getName (false); Czy ja po prostu przesadzę tutaj?
cmcculloh
14

PHP oferuje niezliczone sposoby radzenia sobie z tym problemem, w tym metody magiczne __geti __set, ale wolę jawne metody pobierające i ustawiające. Dlatego:

  1. Walidację można umieścić w seterach (i getterach w tym przypadku)
  2. Intellisense działa z jawnymi metodami
  3. Nie ma wątpliwości, czy właściwość jest tylko do odczytu, tylko do zapisu czy do odczytu i zapisu
  4. Pobieranie właściwości wirtualnych (tj. Obliczonych wartości) wygląda tak samo, jak zwykłe właściwości
  5. Możesz łatwo ustawić właściwość obiektu, która nigdy nie jest nigdzie zdefiniowana, a następnie nie jest udokumentowana
Nieoznakowane mięso
źródło
13

Czy ja po prostu przesadzę tutaj?

Być może ;)

Innym podejściem byłoby wykorzystanie prywatnej / chronionej metody do faktycznego pobierania (buforowanie / db / itp.) Oraz publicznego opakowania, które zwiększa liczbę:

PHP:

public function getName() {
    $this->incrementNameCalled();
    return $this->_getName();
}

protected function _getName() {
    return $this->name;
}

a następnie z samego obiektu:

PHP:

$name = $this->_getName();

W ten sposób nadal możesz użyć tego pierwszego argumentu do czegoś innego (na przykład wysłanie flagi określającej, czy używać tutaj danych z pamięci podręcznej, czy nie).

pix0r
źródło
12

Muszę pominąć ten punkt, dlaczego miałbyś używać gettera wewnątrz obiektu, aby uzyskać dostęp do właściwości tego obiektu?

Podsumowując, getter powinien wywołać metodę pobierającą, która powinna wywołać metodę pobierającą.

Więc powiedziałbym, że wewnątrz metody obiektowej dostęp do właściwości bezpośrednio, zwłaszcza patrząc, że wywołanie innej metody w tym obiekcie (która i tak po prostu uzyska bezpośredni dostęp do właściwości, a następnie ją zwróci) jest tylko bezcelowym, marnotrawnym ćwiczeniem (lub czy źle zrozumiałem pytanie ).

Egg Vans
źródło
Kierowała mną ta sama potrzeba, którą musieliście skomentować ... Plus odpowiedź nie została zamknięta;)
Egg Vans
8

Purystycznym sposobem OO jest unikanie obu i przestrzeganie Prawa Demeter , stosując podejście Powiedz, nie pytaj .

Zamiast pobierać wartość właściwości obiektu, która ściśle wiąże obie klasy, użyj obiektu jako parametru np

  doSomethingWithProperty() {
     doSomethingWith( this.property ) ;
  }

Jeśli właściwość była rodzimym typem, np. Int, użyj metody dostępu, nazwij ją dla domeny problemowej, a nie domeny programowania.

  doSomethingWithProperty( this.daysPerWeek() ) ;

Umożliwi to zachowanie hermetyzacji i wszelkich warunków końcowych lub niezmienników zależnych. Możesz również użyć metody ustawiającej, aby zachować dowolne warunki wstępne lub niezmienniki zależne, jednak nie wpadnij w pułapkę nazywania ich seterami, wróć do zasady Hollywood dotyczącej nazewnictwa podczas używania idiomu.

Martin Spamer
źródło
8

Lepiej jest używać metod akcesorów, nawet w obrębie obiektu. Oto punkty, które natychmiast przychodzą mi do głowy:

  1. Należy to zrobić w celu zachowania spójności z dostępami dokonywanymi z zewnątrz obiektu.

  2. W niektórych przypadkach te metody pomocnicze mogą robić coś więcej niż tylko uzyskiwanie dostępu do pola; mogą wykonywać dodatkowe przetwarzanie (jest to jednak rzadkie). W takim przypadku bezpośredni dostęp do pola oznaczałby, że brakuje tego dodatkowego przetwarzania, a program może się nie powieść, jeśli to przetwarzanie ma być zawsze wykonywane podczas tych dostępów.

Aadith Ramia
źródło
8

Jeśli masz na myśli „najbardziej hermetyzację” przez „purystę”, to zazwyczaj deklaruję wszystkie moje pola jako prywatne, a następnie używam „this.field” z poziomu samej klasy. W przypadku innych klas, w tym podklas, uzyskuję dostęp do stanu instancji za pomocą metod pobierających.

Allain Lalonde
źródło
7

Odkryłem, że używanie seterów / pobierających sprawia, że ​​mój kod jest łatwiejszy do odczytania. Podoba mi się również kontrola, jaką daje, gdy inne klasy używają metod i jeśli zmienię dane, które będzie przechowywać właściwość.

Brendon-Van-Heyzen
źródło
7

Pola prywatne o właściwościach publicznych lub chronionych. Dostęp do wartości powinien przechodzić przez właściwości i być kopiowany do zmiennej lokalnej, jeśli będą używane więcej niż raz w metodzie. Jeśli i TYLKO jeśli masz resztę aplikacji tak całkowicie zmodyfikowaną, wyregulowaną i zoptymalizowaną w inny sposób, aby uzyskać dostęp do wartości przez przeglądanie ich wybranych właściwości, stało się wąskim gardłem (I to nigdy NIGDY się nie zdarzy, zapewniam), jeśli w ogóle zaczniesz rozważyć pozwolenie, by cokolwiek innego niż właściwości bezpośrednio dotykało ich zmiennych bazowych.

Programiści .NET mogą wymusić to za pomocą właściwości automatycznych, ponieważ w czasie projektowania nie można nawet zobaczyć zmiennych bazowych.

Mel
źródło
7

To zależy. To bardziej kwestia stylu niż cokolwiek innego i nie ma twardej zasady.

Steve McLeod
źródło
7

Mogę się mylić, ponieważ jestem samoukiem, ale NIGDY nie korzystam z właściwości publicznych w moich klasach Javy, są one zawsze prywatne lub chronione, więc kod zewnętrzny musi mieć dostęp przez metody pobierające / ustawiające. Jest lepszy do celów konserwacji / modyfikacji. A dla kodu klasy wewnętrznej ... Jeśli metoda getter jest trywialna, używam tej właściwości bezpośrednio, ale zawsze używam metod ustawiających, ponieważ mogę łatwo dodać kod do wyzwalania zdarzeń, jeśli chcę.

Telcontar
źródło
7

Jeśli nie get_property()edytuję właściwości, użyję metody publicznej, chyba że jest to specjalna okazja, taka jak obiekt MySQLi wewnątrz innego obiektu, w którym to przypadku po prostu ustawię właściwość jako publiczną i będę odnosić się do niej jako $obj->object_property.

Wewnątrz obiektu jest zawsze dla mnie właściwość $ this->.

Ross
źródło
5

Wygląda na to, że przy domyślnej implementacji właściwości C # 3.0 decyzja jest podejmowana za Ciebie; MUSISZ ustawić właściwość za pomocą (prawdopodobnie prywatnego) ustawiacza właściwości.

Osobiście używam prywatnego elementu członkowskiego tylko wtedy, gdy nie zrobienie tego spowodowałoby, że obiekt spadłby w mniej niż pożądany stan, na przykład podczas inicjowania lub w przypadku buforowania / leniwego ładowania.

Coincoin
źródło
5

Podoba mi się odpowiedź cmcculloh , ale wydaje się, że najbardziej poprawna jest odpowiedź Grega Hurlmana . Używaj getter / setter przez cały czas, jeśli zacząłeś ich używać od samego początku i / lub jesteś przyzwyczajony do pracy z nimi.

Na marginesie, osobiście uważam, że użycie metody getter / setter ułatwia odczytanie kodu i późniejsze debugowanie.

Robinho
źródło
4

Jak stwierdzono w niektórych komentarzach: Czasami powinieneś, czasami nie. Wspaniałą częścią zmiennych prywatnych jest to, że możesz zobaczyć wszystkie miejsca, w których są używane, gdy coś zmienisz. Jeśli twój getter / setter robi coś, czego potrzebujesz, użyj go. Jeśli to nie ma znaczenia, decydujesz.

Można by zrobić odwrotny przypadek, że jeśli użyjesz metody pobierającej / ustawiającej i ktoś zmieni metodę pobierającą / ustawiającą, musi przeanalizować wszystkie miejsca, w których pobierający i ustawiający są używane wewnętrznie, aby sprawdzić, czy coś zepsuje.

svrist
źródło