Konstruuj jak obiekty w Javie


195

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();
}

9
Zamiast publicznych zmiennych możliwych do przemyślenia, rozważ albo publiczne niezmienne pola, albo zmienne lokalne dla pakietu. Albo byłoby lepiej IMHO.
Peter Lawrey,

Pamiętaj, że chociaż pobierający i ustawiający są brzydcy / gadatliwi, jest to rodzaj serca Javy. To jest nieprecyzyjny język. Z drugiej strony, NIGDY nie powinieneś wpisywać żadnego z nich, ponieważ to właśnie robi dla ciebie IDE. W dynamicznym języku musisz pisać mniej, ale musisz pisać (ogólnie, chociaż IDE mogą pomóc).
Dan Rosenstark

Jak na ironię, podczas gdy OO ma swoje zalety w zakresie enkapsulacji, jest to cena, którą należy zapłacić za procesor i pod względem pamięci. Garbage collector (prawie całkowicie) eliminuje konieczność martwienia się, kiedy odwołania do obiektów powinny zostać usunięte. Obecny trend zatacza koło, stosując off-heap struktur typu C. Jest to idealne rozwiązanie dla rozwiązań typu buforowanie, komunikacji między procesami, szybszych operacji intensywnie wykorzystujących pamięć, niższego GC o / h, a nawet może skorzystać z niższego miejsca o / h dla zestawów danych. Jeśli wiesz, co robisz, nie zadawałbyś tego pytania ... więc pomyśl jeszcze raz!
user924272

@ user924272: Re „Obecny trend zatacza koło, stosując off-kupy struktur typu C”. Co byś zrobił w Javie jak ??? IMHO, jest to obszar, w którym Java pokazuje swój wiek ...
ToolmakerSteve

@ToolmakerSteve - Widzę okrąg. Nie jestem jedyny. Firmy takie jak Azul są nastawione na zbieranie śmieci bez przerw. Java jest stara. Prawdziwe. Inżynierowie, którzy dostrzegają słabość i coś z tym robią, zamiast narzekać? Zasługują na szacunek! +10 do Azul ode mnie :-)
user924272

Odpowiedzi:


62

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:

public property String foo;   
a->Foo = b->Foo;

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


28
To jest tak źle, lubię C # właściwości -Style (co brzmi jak co mówisz)
Jon Onstott

2
Więc użyj przeciążenia ... private int _x; public void x (int value) {_x = wartość; } public int x () {return _x; }
Gordon

12
Wolę mieć możliwość korzystania =, co moim zdaniem czyni kod czystszym.
Svish

6
@ T-Bull: Tylko dlatego, że MOŻESZ mieć dwa xs, 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.
ToolmakerSteve,

2
@ToolmakerSteve: To „może prowadzić do zamieszania” jest najczęstszym i wciąż najsłabszym argumentem, jeśli chodzi o obronę dogmatów kodowania (w przeciwieństwie do stylu kodowania). Zawsze znajdzie się ktoś, kogo MOŻNA pomylić z najprostszymi rzeczami. Zawsze znajdziesz kogoś, kto narzeka, że ​​popełnił błąd po tym, jak nie zasypiał i kodował przez pół tygodnia lub coś takiego, a następnie obwiniał wprowadzający w błąd styl kodowania. Nie pozwalam, żeby to się liczyło. Ten styl jest prawidłowy, oczywisty i utrzymuje przestrzeń nazw w czystości. Poza tym nie ma tu żadnych różnych bytów, wokół nich znajduje się / one / byt i trochę kodu typu „kocioł”.
T-Bull

290

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


88
+1 Za faktyczne posiadanie wiarygodnego źródła. Co drugą odpowiedzią jest to, że ludzie wirują w swoich opiniach, jakby byli faktami.
ArtOfWarfare

1
Istnieje specyfikacja Java Beans, która jest standardowym w branży sposobem uzyskiwania dostępu do właściwości za pomocą metod get and set ... zobacz przegląd en.wikipedia.org/wiki/JavaBeans .
user924272

4
@ user924272: W jaki sposób specyfikacja Java Beans jest istotna dla tej odpowiedzi, która omawia, kiedy właściwe jest użycie „zmiennych instancji publicznej”? Jeśli specyfikacja była standardowym sposobem automatycznego przekształcania zmiennych instancji we właściwości, ala C #, może być istotna. Ale tak nie jest, prawda? Określa jedynie nazwy modułów pobierających i ustawiających płyty kotła, które należy utworzyć, aby wykonać takie mapowanie.
ToolmakerSteve,

@ToolmakerSteve. To jest pytanie java. Pytanie to wymyka się często występującemu problemowi w przypadku specyfikacji. Z perspektywy starej szkoły debugowanie mutacji terenowych jest o wiele łatwiejsze, gdy istnieje standardowy sposób - ustaw punkt przerwania u setera. Prawdopodobnie stało się to przestarzałe w przypadku współczesnych debuggerów, ale jestem zmuszony spoglądać na klasy, które bezpośrednio „uderzają” obiekty ... podczas gdy jest to w porządku w przypadku mniejszych aplikacji, jest to prawdziwy ból głowy dla większych aplikacji i dużych organizacji
user924272

223

Używaj naprawdę zdrowego rozsądku. Jeśli masz coś takiego:

public class ScreenCoord2D{
    public int x;
    public int y;
}

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:

public class BankAccount{
    public int balance;
}

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.


3
Zgadzam się z tą odpowiedzią i mówię dalej, że możesz stworzyć klasę z polami publicznymi, o ile pola są odważne, niezależne od siebie. tzn. jedno pole nie zależy od drugiego. Może to być bardzo przydatne w wielu przypadkach, dla wielu zwracanych wartości z funkcji lub dla polarnych współ-odinianów. {kąt, długość}, które idą w parze, ale nie zależą od siebie w żaden nieodłączny sposób.
Spacen Jasset

@SpacenJasset: FYI, nie rozumiem, w jaki sposób twoje przykłady (wiele wartości zwracanych; współrzędne biegunowe) mają wpływ na to, czy używać pól publicznych w porównaniu z getter / setterami. W przypadku wielu zwracanych wartości może to nawet przynieść efekt przeciwny do zamierzonego, ponieważ prawdopodobnie wywołujący powinien POZYSKIWAĆ tylko zwrócone wartości, co przemawia na korzyść publicznych pobierających i prywatnych ustawiających (niezmiennych). Może to być również prawdą w przypadku zwracania współrzędnych biegunowych z obiektu (x, y) - rozważ AKUMULACYJNE błędy matematyczne, ponieważ zmiany poszczególnych składników współrzędnych biegunowych są konwertowane z powrotem na (x, y).
ToolmakerSteve

@SpacenJasset: Ale zgadzam się z twoją zasadą.
ToolmakerSteve

1
Masz ważny punkt, ale czuję się jak rzecz pikseli jest złym przykładem, ponieważ upewniając się, że piksel jest w oknie (tylko przykład) jest czymś, co ktoś może zrobić, a poza tym, pozwalając ktoś ustawić piksel (-5, -5)może nie być dobry pomysł. :-)
Horsey

50

Aby rozwiązać problemy związane ze zmiennością, możesz zadeklarować xiy jako ostateczne. Na przykład:

class Data {
  public final int x;
  public final int y;
  public Data( int x, int y){
    this.x = x;
    this.y = y;
  }
}

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

public class DataTest {
    public DataTest() {
        Data data1 = new Data(1, 5);
        Data data2 = new Data(2, 4);
        System.out.println(f(data1));
        System.out.println(f(data2));
    }

    public int f(Data d) {
        return (3 * d.x) / d.y;
    }

    public static void main(String[] args) {
        DataTest dataTest = new DataTest();
    }
}

3
Dzięki - odpowiedź, która jest przydatna i zwięzła. Pokazuje, jak uzyskać korzyści ze składni pól, gdy nie chce się zmienności.
ToolmakerSteve

@ToolmakerSteve - dzięki za opinie - bardzo mile widziane.
Brian

Próbowałem użyć końcowych instancji klasy końcowej z polami końcowymi jako strukturalnych „instancji”, ale casedostałem to w wyrażeniu odnoszącym się do takiego pola instancji Case expressions must be constant expressions. Jak to obejść? jaka jest tutaj koncepcja idiomatyczna?
n611x007

1
pola końcowe są nadal odwołaniami do obiektów, które nie są stałymi, ponieważ zostaną zainicjowane przy pierwszym użyciu klasy. Kompilator nie może poznać „wartości” odniesień do obiektu. Stałe muszą być znane podczas kompilacji.
Johan Tidén,

1
+1 Naprawdę ważna odpowiedź. Moim zdaniem nie można nie docenić przydatności niezmiennych klas. Ich semantyka „ognia i zapomnienia” często upraszcza rozumowanie na temat kodu, szczególnie w środowiskach wielowątkowych, w których można je dowolnie udostępniać między wątkami, bez synchronizacji.
TheOperator,

11

Nie używać public pól

Nie używaj publicpól, gdy naprawdę chcesz zawinąć wewnętrzne zachowanie klasy. Weźmy java.io.BufferedReaderna przykład. Ma następujące pole:

private boolean skipLF = false; // If the next character is a line feed, skip it

skipLFjest 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 stan skipLFw trakcie odczytu? BufferedReaderna pewno zwariuje.

Używaj publicpól

Weźmy Pointna przykład tę klasę:

class Point {
    private double x;
    private double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() {
        return this.x;
    }

    public double getY() {
        return this.y;
    }

    public void setX(double x) {
        this.x = x;
    }

    public void setY(double y) {
        this.y = y;
    }
}

To bardzo utrudniłoby obliczenie odległości między dwoma punktami.

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.getX() - a.getX(), 2) + Math.pow(b.getY() - a.getY(), 2));

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:

class Point {
    public double x;
    public double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));

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” :

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 structużyłbyś klasy zamiast (jeśli Java jest obsługiwana struct), to należy ustawić publiczne zmienne instancji klasy.

Oficjalna dokumentacja akceptuje również tę praktykę).


Ponadto, jeśli masz pewność, że członkowie wyższej Pointklasy powinni być niezmienni, możesz dodać finalsłowo kluczowe, aby je wymusić:

public final double x;
public final double y;

8

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).


+1 Dobra wzmianka o problemie - sposób, w jaki wynik nadal NIE jest podobny do struktury C. Jednak podniesiony przez ciebie problem związany z obiektami java zawsze będącymi odniesieniem nie został poprawiony poprzez utworzenie setera zamiast posiadania publicznego pola do zapisu (co jest istotą pytania OP - jakiej reprezentacji użyć). Przeciwnie, jest to argument przemawiający za zrobieniem NIC. Jest to argument ZA NIEZWŁOCNOŚĆ. Można to zrobić albo jako public finalpole, jak w odpowiedzi Briana, albo przez publiczny getter, ale bez publicznego setera. To, czy ktoś używa pól, czy akcesoriów, jest nieistotne.
ToolmakerSteve

8

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.


12
Jak getter / setter rozwiązuje ten problem. Nadal masz odniesienie, nie masz synchronizacji z operacjami. Osoby pobierające / ustawiające same w sobie nie zapewniają ochrony.
he_the_great

1
Operatorzy pobierający i ustawiający mogą zapewnić synchronizację w razie potrzeby. Oczekujesz także, że osoby pobierające i ustawiające zrobią znacznie więcej, niż zostały określone. Niezależnie od tego problem synchronizacji wciąż się poprawia.
user924272

7

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ć:

  • Prawie każde zautomatyzowane narzędzie w świecie Java opiera się na konwencji getter / setter. To samo dotyczy, jak zauważyli inni, tagów jsp, konfiguracji wiosny, narzędzi zaćmienia itp. Itd. ... Walka z tym, czego oczekują twoje narzędzia, jest receptą na długie sesje trollowania przez google próbujące znaleźć ten niestandardowy sposób inicjowania fasolka szparagowa. Naprawdę nie warte kłopotów.
  • Gdy masz już elegancko zakodowaną aplikację z setkami zmiennych publicznych, prawdopodobnie znajdziesz co najmniej jedną sytuację, w której są one niewystarczające - gdzie absolutnie potrzebujesz niezmienności, lub musisz wyzwolić jakieś zdarzenie, gdy zmienna zostanie ustawiona, lub chcesz rzucić wyjątek od zmiany zmiennej, ponieważ ustawia stan obiektu na coś nieprzyjemnego. Utkniesz wtedy w niemożliwych do pozazdroszczenia wyborach między zaśmiecaniem kodu za pomocą specjalnej metody wszędzie tam, gdzie zmienna jest bezpośrednio przywoływana, mając specjalny formularz dostępu dla 3 z 1000 zmiennych w aplikacji.

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


Doskonała dyskusja o problemach zejścia drogą publiczną. Zdecydowana wada Javy, która denerwuje mnie, gdy muszę wrócić do Javy z C # (który nauczył się tutaj z niedogodności Javy).
ToolmakerSteve

4

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ć.


1
+1 za link do artykułu „Dlaczego metody pobierające i ustawiające są złe”. Jednak twoja odpowiedź byłaby jaśniejsza, gdybyś zauważył, że ZARÓWNO publiczne pola ORAZ publiczne obiekty pobierające / ustawiające NIE są JESZCZE sposobem: jak wyjaśniono w tym artykule - jeśli to możliwe, nie rób tego. Zamiast tego zapewnij klientom metody specyficzne dla tego, co muszą zrobić, zamiast odzwierciedlać wewnętrzną reprezentację instancji. JEDNAK tak naprawdę nie odnosi się to do zadawanego pytania (którego należy użyć w przypadku prostej „struktury”), na które lepiej odpowie deweloper, gb i Brian.
ToolmakerSteve

3

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.


ananas rozśmiesza mnie :)
Guillaume

Jednak ta odpowiedź nic nie mówi o tym, czym jest ta różnica. Ragging na niewykwalifikowanych programistach nie pomaga tym programistom wiedzieć, kiedy stworzyć strukturę, a kiedy klasę.
ToolmakerSteve

Nie mówi nic o różnicy, ponieważ autor jest świadomy różnicy (wie, czym jest byt podobny do struktury). Autor pyta, czy użycie struktur jest odpowiednie w języku OO, i mówię tak (w zależności od domeny problemowej). Jeśli pytanie dotyczyło tego, co czyni obiekt prawdziwym przedmiotem domeny, to miałbyś nogę do działania argument.
luis.espinal

Co więcej, jedynym rodzajem niewykwalifikowanego programisty, który nie powinien znać różnicy, byłby ten, który jest jeszcze w szkole. Jest to niezwykle fundamentalne, podobnie jak znajomość różnicy między połączoną listą a tabelą skrótu. Jeśli dana osoba ukończy czteroletnie studia komputerowe, nie wiedząc, co to jest prawdziwy przedmiot, to albo ta osoba nie zostanie odcięta do tej kariery, albo powinna wrócić do szkoły i zażądać zwrotu pieniędzy. Jestem poważny.
luis.espinal

Ale aby zaspokoić twoje narzekanie, udzielę odpowiedzi (która nie ma nic wspólnego z pierwotnym pytaniem i która zasługuje na własny wątek). Obiekty mają zachowanie i stan enkapsulacji. Struktury nie. Obiekty są maszynami stanu. Struktury służą wyłącznie do agregacji danych. Jeśli ludzie chcą bardziej szczegółowej odpowiedzi, mogą swobodnie stworzyć nowe pytanie, w którym możemy rozwinąć je do treści naszych serc.
luis.espinal

2

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.


1
To prawda, ale jeśli używasz Javy, nie stanowi to problemu, ponieważ jednym kliknięciem możesz refaktoryzować całą bazę kodu (Eclipse, Netbeans, prawdopodobnie także VIM i Emacs). Jeśli zdecydowałeś się na jednego z jego dynamicznych przyjaciół, takiego jak Groovy, nawet prosta enkapsulacja może wymagać naprawy na wiele godzin lub dni. Na szczęście będziesz mieć swoje przypadki testowe, które poinformują cię ... o ile więcej kodu musisz naprawić.
Dan Rosenstark

2
Zakładasz oczywiście, że wszyscy użytkownicy znajdują się w twojej bazie kodu, ale oczywiście nie jest to prawdą. Często nawet z różnych nietechnicznych powodów nie jest możliwa zmiana kodu, który może znajdować się we własnej bazie kodu.
Alex Miller

2

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.


2

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

stream.mapToInt(SomeData1::x)

nie jest legalne, ale

stream.mapToInt(SomeData2::getX)

jest.


W tym przypadku możesz użyć data -> data.x, co jest nadal rozsądne
James Kraus

1

Nie widzę krzywdy, jeśli wiesz, że zawsze będzie to prosta struktura i że nigdy nie będziesz chciał przypisywać do niej zachowania.


1

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.


1

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 ...

import java.io.*;

class NameList {
    String name;
    int age;
}

class StructNameAge {
    public static void main(String [] args) throws IOException {

        NameList nl[]=new NameList[5]; // Create new radix of the structure NameList into 'nl' object
        NameList temp=new NameList(); // Create a temporary object of the structure

        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

        /* Enter data into each radix of 'nl' object */

        for(int i=0; i<5; i++) {
            nl[i]=new NameList(); // Assign the structure into each radix

            System.out.print("Name: ");
            nl[i].name=br.readLine();

            System.out.print("Age: ");
            nl[i].age=Integer.parseInt(br.readLine());

            System.out.println();
        }

        /* Perform the sort (Selection Sort Method) */

        for(int i=0; i<4; i++) {
            for(int j=i+1; j<5; j++) {
                if(nl[i].age>nl[j].age) {
                    temp=nl[i];
                    nl[i]=nl[j];
                    nl[j]=temp;
                }
            }
        }

        /* Print each radix stored in 'nl' object */

        for(int i=0; i<5; i++)
            System.out.println(nl[i].name+" ("+nl[i].age+")");
    }
}

Powyższy kod jest wolny od błędów i przetestowany ... Wystarczy skopiować i wkleić go do swojego IDE i ... Wiesz i co ??? :)


0

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.


0

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.


0

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.


0

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.