Strutturare come oggetti in Java


195

È completamente contro il modo Java per creare strutt come oggetti?

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

Vedo una classe con accessori e mutatori più simili a Java.

class SomeData2 {
    int getX();
    void setX(int x);

    int getY();
    void setY(int y);

    private int x;
    private int y;
}

La classe del primo esempio è notoriamente conveniente.

// a function in a class
public int f(SomeData1 d) {
    return (3 * d.x) / d.y;
}

Questo non è così conveniente.

// a function in a class
public int f(SomeData2 d) {
    return (3 * d.getX()) / d.getY();
}

9
Invece di campi mutabili pubblici, considerare campi immutabili pubblici o campi mutabili locali del pacchetto. O sarebbe meglio IMHO.
Peter Lawrey,

Ricorda che, mentre getter e setter sono brutti / dettagliati, è un po 'il cuore di Java. È un linguaggio non conciso. Dall'altro lato, tuttavia, non dovresti MAI digitare nulla di tutto ciò, poiché è quello che fa il tuo IDE per te. In un linguaggio dinamico devi digitare meno, ma devi digitare (in genere, sebbene gli IDE possano essere d'aiuto).
Dan Rosenstark,

Ironia della sorte, mentre OO ha i suoi punti di forza in termini di incapsulamento, questo ha un prezzo da pagare CPU e archiviazione. Il Garbage Collector (quasi completamente) elimina la necessità di preoccuparsi di quando cancellare i riferimenti agli oggetti. La tendenza attuale sta andando al punto di partenza impiegando strutture tipo C fuori dal mucchio. Questo è perfetto per soluzioni di tipo cache, comunicazioni tra processi, operazioni più veloci ad alta intensità di memoria, GC o / he inferiore e può persino beneficiare di una memoria di ore inferiore per i set di dati. Se sai cosa stai facendo, non faresti questa domanda ... quindi ripensaci!
user924272

@ user924272: Ri "La tendenza attuale sta andando al punto di partenza impiegando strutture simili a C fuori dall'heap". Cosa faresti in Java come ??? IMHO, questa è un'area in cui Java sta mostrando la sua età ...
ToolmakerSteve

@ToolmakerSteve -Vedo un cerchio. Non sono il solo. Aziende come Azul sono entusiaste della raccolta dei rifiuti senza pause. Java è vecchio. Vero. Ingegneri che individuano una debolezza e fanno qualcosa al riguardo, piuttosto che lamentarsi? Meritano rispetto! +10 ad Azul da parte mia :-)
user924272

Risposte:


62

Questo è un argomento comunemente discusso. Lo svantaggio della creazione di campi pubblici negli oggetti è che non si ha alcun controllo sui valori impostati su di esso. Nei progetti di gruppo in cui ci sono molti programmatori che usano lo stesso codice, è importante evitare effetti collaterali. Inoltre, a volte è meglio restituire una copia dell'oggetto del campo o trasformarlo in qualche modo ecc. Puoi deridere tali metodi nei tuoi test. Se crei una nuova classe potresti non vedere tutte le azioni possibili. È come una programmazione difensiva: un giorno i getter e i setter potrebbero essere utili e non costa molto crearli / usarli. Quindi a volte sono utili.

In pratica, molti campi hanno getter e setter semplici. Una possibile soluzione sarebbe simile a questa:

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

Aggiornamento: è altamente improbabile che il supporto della proprietà venga aggiunto in Java 7 o forse mai. Altre lingue JVM come Groovy, Scala, ecc. Ora supportano questa funzione. - Alex Miller


28
È un peccato, mi piacciono le proprietà in stile C # (che suona come quello di cui stai parlando)
Jon Onstott

2
Quindi usa il sovraccarico ... private int _x; void pubblico x (valore int) {_x = valore; } public int x () {return _x; }
Gordon,

12
Preferisco essere in grado di utilizzare =, il che a mio avviso rende il codice più pulito.
Svish,

6
@ T-Bull: solo perché PUOI avere due xs che sono due cose diverse, non è una buona idea. IMHO, questo è un suggerimento scarso, in quanto potrebbe creare confusione da parte dei lettori umani. Principio di base: non fare fare un doppio take a un lettore; rendi ovvio ciò che stai dicendo - Usa nomi diversi per entità diverse. Anche se la differenza è semplicemente anteporre un carattere di sottolineatura. Non fare affidamento sulla punteggiatura circostante per differenziare le entità.
ToolmakerSteve

2
@ToolmakerSteve: che "potrebbe portare alla confusione" è l'argomento più comune e ancora più debole quando si tratta di difendere il dogma della codifica (al contrario dello stile di codifica). C'è sempre qualcuno che POTREBBE essere confuso dalle cose più semplici. Troverai sempre qualcuno che si lamenta di aver fatto un errore dopo essere stato sveglio e aver programmato per mezza settimana o qualcosa del genere e aver incolpato lo stile di codifica fuorviante. Non lascio che contino. Quello stile è valido, ovvio e mantiene pulito lo spazio dei nomi. Inoltre, non ci sono entità diverse qui, c'è / one / entity e un po 'di codice boilerplate attorno ad essa.
T-Bull,

290

Sembra che molte persone Java non abbiano familiarità con le Linee guida per la codifica Java Sun che affermano che è del tutto appropriato usare una variabile di istanza pubblica quando la classe è essenzialmente un "Struct", se Java supporta "struct" (quando non c'è alcun comportamento).

Le persone tendono a pensare che getter e setter siano il modo Java, come se fossero al centro di Java. Non è così. Se segui le Linee guida per la codifica di Sun Java, usando le variabili di istanza pubblica in situazioni appropriate, stai effettivamente scrivendo codice migliore che ingombrandolo con getter e setter inutili.

Convenzioni del codice Java del 1999 e ancora invariate.

10.1 Fornitura dell'accesso alle variabili di istanza e di classe

Non rendere pubblica alcuna istanza o variabile di classe senza una buona ragione. Spesso, non è necessario impostare o ottenere esplicitamente le variabili di istanza, come spesso accade come effetto collaterale delle chiamate al metodo.

Un esempio di appropriate variabili di istanza pubblica è il caso in cui la classe è essenzialmente una struttura di dati, senza alcun comportamento. In altre parole, se avessi usato una struttura anziché una classe (se Java supportava la struttura), è opportuno rendere pubbliche le variabili di istanza della classe .

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 Per avere effettivamente una fonte autorevole. Ogni altra risposta è che le persone esprimono le proprie opinioni come se fossero fatti.
ArtOfWarfare il

1
Esiste una specifica Java Beans che è un modo standard del settore di accedere alle proprietà usando i metodi get e set ... vedere en.wikipedia.org/wiki/JavaBeans per una panoramica.
user924272,

4
@ user924272: In che modo le specifiche di Java Beans sono rilevanti per questa risposta, che discute quando è appropriato usare "variabili di istanza pubblica"? Se la specifica fosse un modo standard di trasformare automagicamente le variabili di istanza in proprietà, ala C #, potrebbe essere rilevante. Ma non è vero? Specifica semplicemente la denominazione dei getter e dei setter della piastra di caldaia che dovrebbero essere creati, per realizzare tale mappatura.
ToolmakerSteve

@ToolmakerSteve. Questa è una domanda java. Inoltre, la domanda elude un problema comune in cui esiste una specifica. Dal punto di vista della vecchia scuola, è molto più facile eseguire il debug delle mutazioni sul campo quando esiste un modo standard per farlo: impostare un breakpoint su un setter. Ciò è stato probabilmente reso obsoleto dai debugger moderni, ma sono costretto a disapprovare le classi che "perforano" direttamente gli oggetti ... mentre va bene per le applicazioni più piccole, è un vero mal di testa per le app più grandi e le organizzazioni di grandi dimensioni
user924272

223

Usa il buon senso davvero. Se hai qualcosa come:

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

Quindi ha poco senso avvolgerli in getter e setter. Non memorizzerai mai una coordinata x, y in pixel interi in nessun altro modo. Getter e setter ti rallenteranno solo.

D'altra parte, con:

public class BankAccount{
    public int balance;
}

Potresti voler cambiare il modo in cui un saldo viene calcolato in futuro. Questo dovrebbe davvero usare getter e setter.

È sempre preferibile sapere perché stai applicando le buone pratiche, in modo da sapere quando va bene piegare le regole.


3
Vado d'accordo con questa risposta e dico ulteriormente che è possibile creare una classe con campi pubblici purché i campi siano in grassetto indipendenti l'uno dall'altro. cioè un campo non dipende da un altro. Questo può essere abbastanza utile in molti casi, per più valori di ritorno da una funzione o per i co-odinati polari. {angolo, lunghezza} che vanno insieme ma non dipendono l'uno dall'altro in modo intrinseco.
Spacen Jasset,

@SpacenJasset: Cordiali saluti, non vedo come i tuoi esempi (valori di ritorno multipli; coordinate polari) influiscano sull'uso dei campi pubblici rispetto a getter / setter. Nel caso di più valori di ritorno, potrebbe anche essere controproducente, perché probabilmente il chiamante dovrebbe solo OTTENERE i valori restituiti, il che sostiene a favore di getter pubblici e setter privati ​​(immutabili). Questo potrebbe essere vero anche per il ritorno di coordinate polari da un oggetto (x, y) - considerare gli errori matematici ACCUMULATIVI, poiché le modifiche ai singoli componenti del coord polare vengono riconvertite in (x, y).
ToolmakerSteve

@SpacenJasset: Ma sono d'accordo con il tuo principio.
ToolmakerSteve

1
Hai un punto valido, ma penso che la cosa dei pixel sia un cattivo esempio dal momento che assicurarsi che il pixel sia all'interno della finestra (solo un esempio) è qualcosa che qualcuno potrebbe fare, e inoltre, lasciare che qualcuno lo imposti (-5, -5)potrebbe non essere una buona idea. :-)
Horsey

50

Per risolvere i problemi di mutabilità è possibile dichiarare xey come definitivo. Per esempio:

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

Chiamare il codice che tenta di scrivere in questi campi riceverà un errore di compilazione di "campo x è dichiarato definitivo; non può essere assegnato".

Il codice client può quindi avere la praticità "abbreviata" che hai descritto nel tuo post

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
Grazie - una risposta utile e concisa. Mostra come ottenere il vantaggio della sintassi del campo, quando non si desidera la mutabilità.
ToolmakerSteve

@ToolmakerSteve - grazie per il feedback - molto apprezzato.
Brian,

Ho tentato di usare le istanze finali di una classe finale con campi finali come "istanze" di struttura, ma in caseun'espressione che si riferisce a tale campo di istanza, ho ottenuto Case expressions must be constant expressions. qual è il modo per aggirare questo? qual è il concetto idiomatico qui?
n611x007,

1
i campi finali sono ancora riferimenti ad oggetti, che non sono costanti, poiché verranno inizializzati al primo utilizzo della classe. Il compilatore non può conoscere il "valore" dei riferimenti agli oggetti. Le costanti devono essere note durante la compilazione.
Johan Tidén,

1
+1 Risposta davvero importante. A mio avviso, l'utilità delle classi immutabili non può essere sottovalutata. La loro semantica "ignora e dimentica" rende il ragionamento sul codice spesso più semplice, specialmente in ambienti multithread, dove possono essere condivisi arbitrariamente tra thread, senza sincronizzazione.
TheOperator

11

Non utilizzare i publiccampi

Non usare i publiccampi quando vuoi davvero avvolgere il comportamento interno di una classe. Prendi java.io.BufferedReaderad esempio. Ha il seguente campo:

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

skipLFviene letto e scritto in tutti i metodi di lettura. Cosa succede se una classe esterna in esecuzione in un thread separato ha modificato maliziosamente lo stato di skipLFnel mezzo di una lettura? BufferedReaderandrà sicuramente in tilt.

Usa i publiccampi

Prendi questa Pointclasse per esempio:

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

Ciò renderebbe molto doloroso calcolare la distanza tra due punti.

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

La classe non ha alcun comportamento se non quello di getter e setter. È accettabile utilizzare campi pubblici quando la classe rappresenta solo una struttura di dati e non ha, e non avrà mai un comportamento (qui i getter e setter non sono considerati comportamenti). Può essere scritto meglio in questo modo:

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

Pulito!

Ma ricordate: non solo la classe deve essere assente di comportamento, ma dovrebbe anche avere alcun motivo per avere un comportamento in futuro pure.


(Questo è esattamente ciò che descrive questa risposta . Per citare "Convenzioni del codice per il linguaggio di programmazione Java: 10. Pratiche di programmazione" :

Un esempio di appropriate variabili di istanza pubblica è il caso in cui la classe è essenzialmente una struttura di dati, senza alcun comportamento. In altre parole, se avessi usato una structinvece di una classe (se Java supportato struct), è opportuno rendere pubbliche le variabili di istanza della classe.

Quindi anche la documentazione ufficiale accetta questa pratica.)


Inoltre, se sei sicuro che i membri della Pointclasse precedente dovrebbero essere immutabili, puoi aggiungere una finalparola chiave per farla rispettare:

public final double x;
public final double y;

8

A proposito, la struttura che stai dando come esempio esiste già nella libreria di classi base Java come java.awt.Point. Ha xey come campi pubblici, controlla tu stesso .

Se sai cosa stai facendo e altri nel tuo team lo sanno, allora va bene avere campi pubblici. Ma non dovresti fare affidamento su di esso perché possono causare mal di testa come nei bug relativi agli sviluppatori che usano oggetti come se fossero strutture allocate in pila (gli oggetti java vengono sempre inviati ai metodi come riferimenti e non come copie).


+1 Buona menzione di un problema - un modo in cui il risultato NON è ancora come una struttura C. Tuttavia, il problema che si pone sugli oggetti Java sempre come riferimento, non viene migliorato creando un setter invece di avere un campo scrivibile pubblico (che è l'essenza della domanda di OP - quale rappresentazione usare). Piuttosto, è un argomento a favore del fare NESSUNO. È un argomento per IMMUTABILITÀ. Che può essere fatto come un public finalcampo, come nella risposta di Brian, o avendo un pubblico getter, ma nessun setter pubblico. Cioè, se si usano campi o accessori è irrilevante.
ToolmakerSteve

8

Ri: aku, izb, John Topley ...

Fai attenzione ai problemi di mutabilità ...

Può sembrare ragionevole omettere getter / setter. In realtà potrebbe essere ok in alcuni casi. Il vero problema con il modello proposto mostrato qui è la mutabilità.

Il problema è quando si passa un riferimento ad oggetto contenente campi pubblici non finali. Qualsiasi altra cosa con quel riferimento è libera di modificare quei campi. Non hai più alcun controllo sullo stato di quell'oggetto. (Pensa cosa accadrebbe se le stringhe fossero mutabili.)

Diventa brutto quando quell'oggetto è una parte importante dello stato interno di un altro, hai appena esposto l'implementazione interna. Per evitare ciò, è necessario restituire una copia dell'oggetto. Funziona, ma può causare un'enorme pressione GC da tonnellate di copie monouso create.

Se hai campi pubblici, considera di rendere la classe di sola lettura. Aggiungi i campi come parametri al costruttore e contrassegna i campi come finali. Altrimenti assicurati di non esporre lo stato interno e, se devi costruire nuove istanze per un valore di ritorno, assicurati che non venga chiamato in modo eccessivo.

Vedi: " Effective Java " di Joshua Bloch - Articolo # 13: Favor Immutability.

PS: Tenete anche presente che tutte le JVM in questi giorni ottimizzeranno getMethod, se possibile, risultando in una singola istruzione di lettura sul campo.


12
In che modo un getter / setter risolve questo problema. Hai ancora un riferimento, non hai alcuna sincronizzazione con le operazioni. Getter / setter non offrono protezione in sé e per sé.
he_the_great

1
Getter e setter possono fornire la sincronizzazione, se necessario. Ti aspetti anche che i getter e il setter facciano molto più di quanto non fosse specificato. Indipendentemente da ciò, il problema della sincronizzazione rimane ancora.
user924272,

7

Ho provato questo in alcuni progetti, sulla base della teoria secondo cui getter e setter ingombrano il codice con una semiflessione insignificante, e che altri linguaggi sembrano andare bene con il nascondimento dei dati basato su convenzioni o il partizionamento delle responsabilità (ad esempio python).

Come altri hanno già notato sopra, ci sono 2 problemi che si verificano e non sono davvero risolvibili:

  • Quasi tutti gli strumenti automatizzati nel mondo Java si basano sulla convenzione getter / setter. Idem per, come notato da altri, tag jsp, configurazione a molla, strumenti per eclissi, ecc. Ecc. Combattere contro ciò che i tuoi strumenti si aspettano di vedere è una ricetta per lunghe sessioni che trollano attraverso Google cercando di trovare quel modo non standard di iniziare fagioli di primavera. Davvero non vale la pena.
  • Una volta che hai la tua applicazione elegantemente codificata con centinaia di variabili pubbliche, troverai probabilmente almeno una situazione in cui sono insufficienti, in cui hai assolutamente bisogno dell'immutabilità o devi attivare un evento quando viene impostata la variabile o vuoi lanciare un'eccezione su una modifica variabile perché imposta uno stato dell'oggetto su qualcosa di spiacevole. Sei quindi bloccato con le scelte non invidiabili tra ingombrare il tuo codice con un metodo speciale ovunque la variabile sia direttamente referenziata, con un modulo di accesso speciale per 3 delle 1000 variabili nella tua applicazione.

E questo è, nel migliore dei casi, lo scenario di lavorare interamente in un progetto privato autonomo. Una volta esportato tutto in una biblioteca accessibile al pubblico, questi problemi diventeranno ancora più grandi.

Java è molto prolisso e questa è una cosa allettante da fare. Non farlo


Ottima discussione dei problemi di percorrere la strada dei campi pubblici. Una carenza definitiva di Java, che mi dà fastidio quando devo tornare a Java da C # (che ho imparato dall'inconveniente di Java qui).
ToolmakerSteve

4

Se il modo Java è il modo OO, quindi sì, la creazione di una classe con campi pubblici infrange i principi che riguardano il nascondere le informazioni che dicono che un oggetto dovrebbe gestire il proprio stato interno. (Quindi non sto solo gettandoti un gergo su di te, un vantaggio del nascondere le informazioni è che i meccanismi interni di una classe sono nascosti dietro un'interfaccia: supponi di voler cambiare il meccanismo con cui la tua classe struct ha salvato uno dei suoi campi, probabilmente dovrai tornare indietro e cambiare le classi che usano la classe ...)

Inoltre, non puoi trarre vantaggio dal supporto per le classi conformi alla denominazione JavaBean, il che danneggerà se decidi, per esempio, di usare la classe in una Pagina Java Server scritta in Expression Language.

L'articolo di JavaWorld Perché i metodi Getter e Setter sono articoli malvagi potrebbe anche interessarti a pensare a quando non implementare metodi di accesso e mutatore.

Se stai scrivendo una piccola soluzione e vuoi ridurre al minimo la quantità di codice coinvolto, il modo Java potrebbe non essere il modo giusto - immagino che dipenda sempre da te e dal problema che stai cercando di risolvere.


1
+1 per il collegamento all'articolo "Perché i metodi Getter e Setter sono malvagi". Tuttavia, la tua risposta sarebbe stata più chiara se avessi sottolineato che ENTRAMBI i campi pubblici E i getter / setter pubblici NON SONO INOLTRE il modo Java: come spiegato in quell'articolo - quando possibile, non farlo neanche. Fornisci invece ai clienti metodi specifici per ciò che devono fare, piuttosto che rispecchiare la rappresentazione interna dell'istanza. TUTTAVIA, questo non affronta realmente la domanda che viene posta (quale usare, per un semplice caso "struct"), a cui risponde meglio lo sviluppatore.g, izb e Brian.
ToolmakerSteve

3

Non c'è nulla di sbagliato in quel tipo di codice, a condizione che l'autore sappia che sono strutture (o navette dati) invece di oggetti. Molti sviluppatori Java non sono in grado di distinguere tra un oggetto ben formato (non solo una sottoclasse di java.lang.Object, ma un vero oggetto in un dominio specifico) e un ananas. Ergo, finiscono per scrivere le strutture quando hanno bisogno di oggetti e viceversa.


l'ananas mi fa ridere :)
Guillaume

Tuttavia, questa risposta non dice nulla su quale sia questa differenza. Il ragging su sviluppatori non qualificati non aiuta quegli sviluppatori a sapere quando creare una struttura e quando creare una classe.
ToolmakerSteve

Non dice nulla sulla differenza perché l'autore è consapevole della differenza (sa che cosa è un'entità strutturale). L'autore sta chiedendo se l'uso delle strutture sia appropriato in un linguaggio OO, e io dico di sì (a seconda del dominio del problema). Se la domanda riguardasse cosa rende un oggetto un oggetto di dominio reale, allora avresti una gamba da mettere nel tuo discussione.
luis.espinal,

Inoltre, l'unico tipo di sviluppatore non specializzato che non dovrebbe conoscere la differenza sarebbe quello che è ancora a scuola. Questo è estremamente fondamentale, come conoscere la differenza tra un elenco collegato e una tabella hash. Se una persona si laurea con una laurea in software di 4 anni senza sapere cosa sia un vero oggetto, allora quella persona non è tagliata per questa carriera, o dovrebbe tornare a scuola e chiedere un rimborso. Sono serio.
luis.espinal,

Ma per soddisfare la tua lamentela fornirò una risposta (che ha poco a che fare con la domanda originale e che merita il suo thread). Gli oggetti hanno comportamento e incapsulano lo stato. Le strutture no. Gli oggetti sono macchine a stati. Le strutture sono solo per aggregare i dati. Se le persone vogliono una risposta più elaborata, sono libere di creare una nuova domanda in cui possiamo approfondirla al contenuto dei nostri cuori.
luis.espinal,

2

Il problema con l'uso dell'accesso al campo pubblico è lo stesso problema dell'uso di un nuovo metodo anziché di un metodo di fabbrica: se cambi idea in seguito, tutti i chiamanti esistenti vengono interrotti. Quindi, dal punto di vista dell'evoluzione dell'API, di solito è una buona idea mordere il proiettile e usare getter / setter.

Un posto in cui vado dall'altra parte è quando controlli fortemente l'accesso alla classe, ad esempio in una classe statica interna utilizzata come struttura di dati interna. In questo caso, potrebbe essere molto più chiaro utilizzare l'accesso al campo.

A proposito, su asserzione di e-bartek, è altamente improbabile che IMO aggiunga supporto di proprietà in Java 7.


1
Questo è vero, ma se stai usando Java non è un problema, dal momento che puoi refactoring di un'intera base di codice con un clic (Eclipse, Netbeans, probabilmente anche VIM ed Emacs). Se hai optato per uno dei suoi amici dinamici, come Groovy, anche un semplice incapsulamento potrebbe farti aggiustare per ore o giorni. Fortunatamente avresti i tuoi casi di test che ti informerebbero ... quanto altro codice devi correggere.
Dan Rosenstark,

2
Ovviamente supponi che tutti gli utenti siano nella tua base di codice, ma ovviamente ciò spesso non è vero. Spesso non è nemmeno possibile per vari motivi non tecnici modificare il codice che potrebbe trovarsi nella propria base di codice.
Alex Miller,

2

Uso spesso questo modello durante la creazione di classi interne private per semplificare il mio codice, ma non consiglierei di esporre tali oggetti in un'API pubblica. In generale, più frequentemente è possibile rendere immutabili gli oggetti nell'API pubblica e meglio non è possibile costruire l'oggetto "simile a una struttura" in modo immutabile.

Per inciso, anche se stessi scrivendo questo oggetto come una classe interna privata, fornirei comunque un costruttore per semplificare il codice per inizializzare l'oggetto. Dover avere 3 righe di codice per ottenere un oggetto utilizzabile quando uno lo farà è semplicemente disordinato.


2

Una domanda molto antica, ma lasciatemi dare un altro breve contributo. Java 8 ha introdotto espressioni lambda e riferimenti a metodi. Le espressioni lambda possono essere semplici riferimenti a metodi e non dichiarare un corpo "vero". Ma non è possibile "convertire" un campo in un riferimento di metodo. così

stream.mapToInt(SomeData1::x)

non è legale, ma

stream.mapToInt(SomeData2::getX)

è.


In questo caso puoi usare data -> data.x, il che è ancora ragionevole
James Kraus,

1

Non vedo il danno se sai che sarà sempre una struttura semplice e che non vorrai mai attaccare il comportamento ad esso.


1

Questa è una domanda sul design orientato agli oggetti, non su Java il linguaggio. In genere è buona norma nascondere i tipi di dati all'interno della classe ed esporre solo i metodi che fanno parte dell'API della classe. Se esponi tipi di dati interni, non potrai mai cambiarli in futuro. Se li nascondi, l'unico obbligo nei confronti dell'utente è la restituzione del metodo e i tipi di argomento.


1

Qui creo un programma per inserire Nome ed Età di 5 persone diverse ed eseguire un ordinamento di selezione (in base all'età). Ho usato una classe che funge da struttura (come il linguaggio di programmazione C) e una classe principale per eseguire l'operazione completa. Di seguito fornisco il codice ...

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+")");
    }
}

Il codice sopra è privo di errori e testato ... Basta copiarlo e incollarlo nell'IDE e ... Sai e cosa ??? :)


0

Puoi creare una classe semplice con campi pubblici e senza metodi in Java, ma è ancora una classe ed è ancora gestita sintatticamente e in termini di allocazione della memoria proprio come una classe. Non c'è modo di riprodurre autenticamente le strutture in Java.


0

A volte uso tale classe, quando devo restituire più valori da un metodo. Naturalmente, tale oggetto ha una vita breve e una visibilità molto limitata, quindi dovrebbe essere OK.


0

Come per la maggior parte delle cose, c'è la regola generale e poi ci sono circostanze specifiche. Se stai eseguendo un'applicazione chiusa e acquisita in modo da sapere come verrà utilizzato un determinato oggetto, puoi esercitare più libertà per favorire la visibilità e / o l'efficienza. Se stai sviluppando una classe che verrà utilizzata pubblicamente da altri al di fuori del tuo controllo, allora inclinati verso il modello getter / setter. Come per tutte le cose, basta usare il buon senso. Spesso va bene fare un giro iniziale con i pubblici e poi cambiarli in getter / setter in seguito.


0

La programmazione orientata all'aspetto ti consente di intercettare compiti o recuperi e allegare loro la logica di intercettazione, che propongo sia il modo giusto per risolvere il problema. (La questione se debbano essere pubblici o protetti o protetti dai pacchetti è ortogonale.)

Quindi inizi con campi non intercettati con il giusto qualificatore di accesso. Man mano che crescono i requisiti del programma, si allega la logica per forse convalidare, creare una copia dell'oggetto da restituire, ecc.

La filosofia getter / setter impone costi su un gran numero di casi semplici in cui non sono necessari.

Il fatto che l'aspetto sia più pulito o meno è in qualche modo qualitativo. Troverei facile vedere solo le variabili in una classe e visualizzare la logica separatamente. In effetti, la ragion d'essere per la programmazione orientata ad Apect è che molte preoccupazioni sono trasversali e compartimentarle nel corpo della classe in sé non è l'ideale (la registrazione è un esempio - se vuoi registrare tutto ciò che Java vuole che tu voglia) scrivere un sacco di getter e mantenerli sincronizzati ma AspectJ ti consente di creare una riga.

Il problema dell'IDE è un'aringa rossa. Non è tanto la tipizzazione quanto la lettura e l'inquinamento visivo che deriva da get / sets.

Le annotazioni sembrano simili alla programmazione orientata all'aspetto a prima vista, tuttavia richiedono di enumerare in modo esaustivo i tagli di punti collegando le annotazioni, al contrario di una concisa specifica del tipo di carattere jolly in AspectJ.

Spero che la consapevolezza di AspectJ impedisca alle persone di stabilirsi prematuramente su linguaggi dinamici.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.