Czy tworzenie obiektów podobnych do struktury jest całkowicie sprzeczne z Javą?
class SomeData1 {
public int x;
public int y;
}
Widzę klasę z akcesoriami i mutatorami bardziej podobnymi do Javy.
class SomeData2 {
int getX();
void setX(int x);
int getY();
void setY(int y);
private int x;
private int y;
}
Klasa z pierwszego przykładu jest wygodna pod względem notacyjnym.
// a function in a class
public int f(SomeData1 d) {
return (3 * d.x) / d.y;
}
To nie jest tak wygodne.
// a function in a class
public int f(SomeData2 d) {
return (3 * d.getX()) / d.getY();
}
Odpowiedzi:
To często omawiany temat. Wadą tworzenia pól publicznych w obiektach jest to, że nie masz kontroli nad ustawionymi dla nich wartościami. W projektach grupowych, w których jest wielu programistów używających tego samego kodu, ważne jest, aby unikać skutków ubocznych. Poza tym czasem lepiej jest zwrócić kopię obiektu pola lub jakoś go przekształcić itp. Możesz wyśmiewać takie metody w swoich testach. Jeśli utworzysz nową klasę, możesz nie zobaczyć wszystkich możliwych działań. To jest jak programowanie defensywne - kiedyś gettery i setery mogą być pomocne i ich tworzenie / używanie nie kosztuje dużo. Czasami są więc przydatne.
W praktyce większość pól ma proste getery i setery. Możliwe rozwiązanie wyglądałoby tak:
Aktualizacja: Jest bardzo mało prawdopodobne, że obsługa właściwości zostanie dodana w Javie 7 lub być może kiedykolwiek. Inne języki JVM, takie jak Groovy, Scala itp., Obsługują teraz tę funkcję. - Alex Miller
źródło
=
, co moim zdaniem czyni kod czystszym.x
s, które są dwiema różnymi rzeczami, nie jest to dobry pomysł. IMHO, to kiepska sugestia, ponieważ może prowadzić do zamieszania wśród ludzkich czytelników. Podstawowa zasada: nie zmuszaj czytelnika do podwójnego podejścia; wyraź to, co mówisz - używaj różnych nazw dla różnych podmiotów. Nawet jeśli różnica polega jedynie na podkreśleniu. Nie polegaj na otaczających znakach interpunkcyjnych, aby odróżnić byty.Wygląda na to, że wiele osób Java nie zna Wytycznych Sun Java Coding Guidelines, które mówią, że całkiem właściwe jest używanie publicznej zmiennej instancji, gdy klasa jest zasadniczo „Struct”, jeśli Java obsługuje „struct” (gdy nie ma żadnego zachowania).
Ludzie myślą, że osoby pobierające i ustawiające są w języku Java, tak jakby były sercem Javy. Tak nie jest. Jeśli postępujesz zgodnie ze wskazówkami dotyczącymi kodowania Sun Java, używając zmiennych instancji publicznej w odpowiednich sytuacjach, w rzeczywistości piszesz lepszy kod niż zaśmiecanie go niepotrzebnymi modułami pobierającymi i ustawiającymi.
Konwencje kodu Java z 1999 roku i wciąż niezmienione.
10.1 Zapewnienie dostępu do zmiennych instancji i klas
Nie upubliczniaj żadnej instancji ani zmiennej klasy bez uzasadnionego powodu. Często zmienne instancji nie muszą być jawnie ustawiane ani często uzyskiwane, co dzieje się jako efekt uboczny wywołań metod.
Jednym z przykładów odpowiednich zmiennych instancji publicznej jest przypadek, w którym klasa jest zasadniczo strukturą danych, bez zachowania. Innymi słowy, jeśli użyłbyś struct zamiast klasy (jeśli Java obsługuje struct), to należy upublicznić zmienne instancji klasy .
http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177
http://en.wikipedia.org/wiki/Plain_old_data_structure
http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28
źródło
Używaj naprawdę zdrowego rozsądku. Jeśli masz coś takiego:
Wtedy nie ma sensu zawijać ich w gettery i setery. Nigdy nie będziesz przechowywać współrzędnej x, y w pełnych pikselach w żaden inny sposób. Getters i setery spowalniają cię.
Z drugiej strony:
W przyszłości możesz chcieć zmienić sposób obliczania salda. To naprawdę powinno używać pobierających i ustawiających.
Zawsze lepiej jest wiedzieć, dlaczego stosujesz dobre praktyki, abyś wiedział, kiedy możesz nagiąć reguły.
źródło
(-5, -5)
może nie być dobry pomysł. :-)Aby rozwiązać problemy związane ze zmiennością, możesz zadeklarować xiy jako ostateczne. Na przykład:
Wywołanie kodu, który próbuje zapisać się w tych polach, otrzyma błąd czasu kompilacji „pole x jest ostateczne; nie można go przypisać”.
Kod klienta może wtedy mieć wygodę „krótkiej ręki” opisaną w poście
źródło
case
dostałem to w wyrażeniu odnoszącym się do takiego pola instancjiCase expressions must be constant expressions
. Jak to obejść? jaka jest tutaj koncepcja idiomatyczna?Nie używać
public
pólNie używaj
public
pól, gdy naprawdę chcesz zawinąć wewnętrzne zachowanie klasy. Weźmyjava.io.BufferedReader
na przykład. Ma następujące pole:skipLF
jest odczytywany i zapisywany we wszystkich metodach odczytu. Co się stanie, jeśli klasa zewnętrzna działająca w osobnym wątku złośliwie zmodyfikuje stanskipLF
w trakcie odczytu?BufferedReader
na pewno zwariuje.Używaj
public
pólWeźmy
Point
na przykład tę klasę:To bardzo utrudniłoby obliczenie odległości między dwoma punktami.
Klasa nie ma żadnego innego zachowania niż zwykłe metody pobierające i ustawiające. Dopuszczalne jest stosowanie pól publicznych, gdy klasa reprezentuje tylko strukturę danych, a nie ma i nigdy nie będzie zachowywać się (cienkie elementy pobierające i ustawiające nie są tutaj uważane za zachowanie). Można to lepiej napisać w ten sposób:
Czysty!
Ale pamiętaj: Nie tylko klasa musi być nieobecny zachowania, ale powinno także mieć żadnego powodu, aby mieć zachowań w przyszłości.
(Dokładnie to opisuje ta odpowiedź . Cytując „Konwencje kodu dla języka programowania Java: 10. Praktyki programowania” :
Oficjalna dokumentacja akceptuje również tę praktykę).
Ponadto, jeśli masz pewność, że członkowie wyższej
Point
klasy powinni być niezmienni, możesz dodaćfinal
słowo kluczowe, aby je wymusić:źródło
Nawiasem mówiąc, struktura, którą podajesz jako przykład, już istnieje w bibliotece klas bazowych Java as
java.awt.Point
. Ma xiy jako pola publiczne, sprawdź to sam .Jeśli wiesz, co robisz, a inni w Twoim zespole wiedzą o tym, możesz mieć pola publiczne. Ale nie powinieneś na nim polegać, ponieważ mogą powodować bóle głowy, jak w przypadku błędów związanych z programistami używającymi obiektów tak, jakby były strukturami przydzielonymi do stosu (obiekty java są zawsze wysyłane do metod jako referencje, a nie jako kopie).
źródło
public final
pole, jak w odpowiedzi Briana, albo przez publiczny getter, ale bez publicznego setera. To, czy ktoś używa pól, czy akcesoriów, jest nieistotne.Re: aku, izb, John Topley ...
Uważaj na problemy ze zmiennością ...
Może się wydawać rozsądne pominięcie pobierających / ustawiających. W niektórych przypadkach może być w porządku. Prawdziwym problemem z przedstawionym tutaj proponowanym wzorem jest zmienność.
Problem polega na tym, że po przekazaniu odwołania do obiektu zawierającego nieoficjalne, publiczne pola. Wszystko inne z tym odniesieniem może modyfikować te pola. Nie masz już żadnej kontroli nad stanem tego obiektu. (Pomyśl, co by się stało, gdyby struny były zmienne).
Robi się źle, gdy ten obiekt jest ważną częścią stanu wewnętrznego innego, właśnie odkryłeś wewnętrzną implementację. Aby temu zapobiec, zamiast tego należy zwrócić kopię obiektu. To działa, ale może powodować ogromny nacisk GC z ton utworzonych kopii jednorazowego użytku.
Jeśli masz pola publiczne, rozważ uczynienie klasy tylko do odczytu. Dodaj pola jako parametry do konstruktora i zaznacz pola jako końcowe. W przeciwnym razie upewnij się, że nie ujawniasz stanu wewnętrznego, a jeśli musisz skonstruować nowe wystąpienia wartości zwracanej, upewnij się, że nie zostanie ona wywołana nadmiernie.
Zobacz: „ Efektywna Java ” Joshua Blocha - Punkt 13: Sprzyjanie niezmienności.
PS: Pamiętaj też, że wszystkie JVM w dzisiejszych czasach zoptymalizują getMethod, jeśli to możliwe, w wyniku czego powstanie tylko jedna instrukcja odczytu pola.
źródło
Próbowałem tego w kilku projektach, w oparciu o teorię, że programy pobierające i ustawiające zaśmiecają kod semantycznie bezsensownym cruftem, a inne języki wydają się dobrze z ukrywaniem danych lub podziałem obowiązków na podstawie konwencji (np. Python).
Jak zauważyli inni powyżej, napotkacie 2 problemy i nie da się ich naprawić:
I to w najlepszym przypadku jest scenariusz polegający na pracy w ramach niezależnego projektu prywatnego. Po wyeksportowaniu całości do publicznie dostępnej biblioteki problemy te staną się jeszcze większe.
Java jest bardzo gadatliwa i jest to kuszące. Nie rób tego
źródło
Jeśli metoda Java jest metodą OO, to tak, utworzenie klasy z polami publicznymi łamie zasady dotyczące ukrywania informacji, które mówią, że obiekt powinien zarządzać własnym stanem wewnętrznym. (Ponieważ nie mówię do ciebie tylko żargonem, zaletą ukrywania informacji jest to, że wewnętrzne funkcje klasy są ukryte za interfejsem - powiedz, że chcesz zmienić mechanizm, za pomocą którego klasa strukturalna zapisała jedno z jej pól, prawdopodobnie będziesz musiał wrócić i zmienić wszystkie klasy, które korzystają z tej klasy ...)
Nie możesz również skorzystać ze wsparcia dla klas zgodnych z nazewnictwem JavaBean, co zaszkodzi, jeśli zdecydujesz się, na przykład, użyć klasy na stronie JavaServer napisanej przy użyciu języka wyrażeń.
Artykuł w JavaWorld Dlaczego metody Gettera i Settera są złe może zainteresować Cię również, kiedy nie wdrożysz metod dostępu i mutatora.
Jeśli piszesz małe rozwiązanie i chcesz zminimalizować ilość kodu, sposób Java może nie być właściwy - myślę, że zawsze zależy od Ciebie i problemu, który próbujesz rozwiązać.
źródło
Nie ma nic złego w tego typu kodzie, pod warunkiem, że autor wie, że to struktury (lub transfer danych) zamiast obiektów. Wielu programistów Java nie potrafi odróżnić dobrze uformowanego obiektu (nie tylko podklasy java.lang.Object, ale prawdziwego obiektu w określonej domenie) od ananasa. Ergo, w końcu piszą struktury, gdy potrzebują przedmiotów i viceversa.
źródło
Problem z korzystaniem z publicznego dostępu do pola jest taki sam, jak w przypadku korzystania z nowej zamiast metody fabrycznej - jeśli później zmienisz zdanie, wszyscy obecni rozmówcy zostaną zerwani. Tak więc, z punktu widzenia ewolucji API, zwykle dobrym pomysłem jest ugryzienie kuli i użycie getterów / setterów.
Jednym z miejsc, gdzie idę w drugą stronę, jest silna kontrola dostępu do klasy, na przykład w wewnętrznej klasie statycznej używanej jako wewnętrzna struktura danych. W takim przypadku korzystanie z dostępu do pola może być znacznie łatwiejsze.
Nawiasem mówiąc, według twierdzenia e-bartek jest wysoce nieprawdopodobne, aby IMO dodało obsługę właściwości w Javie 7.
źródło
Często używam tego wzorca podczas budowania prywatnych klas wewnętrznych, aby uprościć mój kod, ale nie zalecałbym ujawniania takich obiektów w publicznym interfejsie API. Ogólnie rzecz biorąc, im częściej można uczynić obiekty w publicznym interfejsie API niezmiennymi, tym lepiej i nie jest możliwe zbudowanie obiektu „podobnego do strukturalnego” w niezmienny sposób.
Nawiasem mówiąc, nawet gdybym pisał ten obiekt jako prywatną klasę wewnętrzną, nadal zapewniałbym konstruktora, aby uprościć kod inicjujący obiekt. Konieczność posiadania 3 linii kodu, aby uzyskać użyteczny obiekt, gdy się to zrobi, jest po prostu bałagan.
źródło
Bardzo, bardzo stare pytanie, ale pozwólcie, że zrobię kolejny krótki wkład. Java 8 wprowadziła wyrażenia lambda i odwołania do metod. Wyrażenia lambda mogą być prostymi odniesieniami do metod i nie mogą deklarować „prawdziwej” treści. Ale nie można „przekonwertować” pola na odwołanie do metody. A zatem
nie jest legalne, ale
jest.
źródło
data -> data.x
, co jest nadal rozsądneNie widzę krzywdy, jeśli wiesz, że zawsze będzie to prosta struktura i że nigdy nie będziesz chciał przypisywać do niej zachowania.
źródło
To pytanie dotyczy projektowania obiektowego, a nie języka Java. Zasadniczo dobrą praktyką jest ukrywanie typów danych w klasie i ujawnianie tylko metod, które są częścią interfejsu API klasy. Jeśli ujawnisz wewnętrzne typy danych, nigdy nie możesz ich zmienić w przyszłości. Jeśli je ukryjesz, jedynym obowiązkiem użytkownika jest zwrot metody i typy argumentów.
źródło
Tutaj tworzę program do wprowadzania imienia i wieku 5 różnych osób i przeprowadzam sortowanie według wyboru (według wieku). Użyłem klasy, która działa jako struktura (jak język programowania C) i klasy głównej do wykonania całej operacji. Poniżej dostarczam kod ...
Powyższy kod jest wolny od błędów i przetestowany ... Wystarczy skopiować i wkleić go do swojego IDE i ... Wiesz i co ??? :)
źródło
Możesz stworzyć prostą klasę z polami publicznymi i bez metod w Javie, ale nadal jest klasą i nadal jest obsługiwana składniowo i pod względem alokacji pamięci, tak jak klasa. Nie ma sposobu na autentyczne odtwarzanie struktur w Javie.
źródło
Kiedyś używam takiej klasy, gdy muszę zwrócić wiele wartości z metody. Oczywiście taki obiekt jest krótkotrwały i ma bardzo ograniczoną widoczność, więc powinien być OK.
źródło
Podobnie jak w przypadku większości rzeczy, istnieje ogólna zasada, a następnie są szczególne okoliczności. Jeśli wykonujesz zamkniętą, przechwyconą aplikację, aby wiedzieć, w jaki sposób dany obiekt będzie używany, możesz skorzystać z większej swobody, aby sprzyjać widoczności i / lub wydajności. Jeśli opracowujesz klasę, która będzie publicznie wykorzystywana przez osoby poza twoją kontrolą, to pochyl się w kierunku modelu pobierającego / ustawiającego. Podobnie jak w przypadku wszystkich rzeczy, kieruj się zdrowym rozsądkiem. Często dobrze jest zrobić pierwszą rundę z publiką, a następnie zmienić ją na getter / setters później.
źródło
Programowanie zorientowane na aspekty pozwala uwięzić przypisania lub pobrania i dołączyć do nich logikę przechwytywania, co, moim zdaniem, jest właściwym sposobem rozwiązania problemu. (Kwestia, czy powinny być publiczne, chronione czy chronione pakietowo, jest ortogonalna.)
W ten sposób zaczynasz od nieprzechwyconych pól z odpowiednim kwalifikatorem dostępu. W miarę wzrostu wymagań programu dołączasz logikę, aby być może sprawdzić, wykonać kopię zwracanego obiektu itp.
Filozofia getter / setter nakłada koszty na dużą liczbę prostych przypadków, w których nie są one potrzebne.
To, czy styl aspektu jest czystszy, czy nie, jest nieco jakościowe. Łatwo byłoby mi zobaczyć tylko zmienne w klasie i osobno zobaczyć logikę. W rzeczywistości racją bytu programowania zorientowanego na Apect jest to, że wiele problemów ma charakter przekrojowy, a dzielenie ich na przedziały w samym ciele klasy nie jest idealne (logowanie jest przykładem - jeśli chcesz się zalogować, to Java chce, abyś napisz całą grupę getterów i utrzymuj je w synchronizacji, ale AspectJ pozwala ci na jedną linijkę).
Problem IDE to śledź czerwony. To nie tyle pisanie na maszynie, co czytanie i zanieczyszczenie wizualne, które powstaje w wyniku get / set.
Adnotacje na pierwszy rzut oka wydają się podobne do programowania aspektowego, jednak wymagają wyczerpującego wyliczenia skrótów punktów poprzez dołączanie adnotacji, w przeciwieństwie do zwięzłej specyfikacji punktowej przypominającej symbole wieloznaczne w AspectJ.
Mam nadzieję, że znajomość AspectJ zapobiega przedwczesnemu osiedlaniu się w dynamicznych językach.
źródło