Anonimi vs classi interne nominate? – migliori pratiche?

Ho una class, chiamiamola LineGraph, che rende un grafico a linee. Devo creare una sottoclass, ma la class derivata è usata solo in un posto ed è accoppiata alla class che lo usa. Quindi sto usando una class interiore.

Vedo due modi per farlo:

Classe interiore anonima

public class Gui { LineGraph graph = new LineGraph() { // extra functionality here. }; } 

Nominato class interiore

 public class Gui { MyLineGraph graph = new MyLineGraph(); private class MyLineGraph extends LineGraph { // extra functionality here. } } 

Non sono un fan delle classi interne anonime, perché francamente penso che sia davvero brutto. Ma nel caso di una sottoclass che è usata solo in un posto, c’è un overkill di class interna chiamato? Qual è la pratica accettata?

Un vantaggio delle classi interne anonime è che nessuno può mai usarlo da nessun’altra parte, mentre una class interna con nome può essere usata (se solo dalla class che l’ha creata se resa privata). È una piccola distinzione, ma significa che puoi proteggere una class interiore dall’essere usata accidentalmente altrove.

Inoltre, l’uso della class interna anonima dà a chiunque leggendo il tuo codice un vantaggio – “questa class viene usata solo qui e da nessun’altra parte”. Se vedi una class interna con nome, qualcuno potrebbe pensare che sarebbe stata usata in più punti della class.

Sono molto simili, quindi nessuno dei due punti è un punto di svolta. Penso che sia d’aiuto per chiarezza se si usano classi interne anonime per una tantum e si chiamano classi interne quando vengono utilizzate più volte all’interno della class.

(Contrasto a Daniel Lew)

Uno svantaggio delle classi interne anonime è che nessuno può mai usarlo da nessun’altra parte, mentre una class interna con nome può essere usata (se solo dalla class che l’ha creata se resa privata). È una piccola distinzione, ma significa che puoi contribuire ad assicurare che una class interiore non venga ricreata casualmente altrove.

Inoltre, l’uso della class interna anonima dà a chiunque leggendo il tuo codice un periodo più difficile, in quanto deve analizzare questa class che è uscita dal nulla. Usando una class interna chiamata puoi organizzare di più la sorgente.

Ho visto casi in cui ci sono due (o più) classi interne anonime con lo stesso identico codice. In particolare nelle GUI (dove potresti avere più controlli che eseguono la stessa azione) questo può apparire (e sto parlando di codice di produzione, non di codice scritto dai miei studenti).

Il problema della leggibilità va in entrambe le direzioni, alcune persone trovano meglio le classi interne anonime in quanto consentono di vedere cosa succede in una volta, mentre altri la trovano una distrazione. Questa parte si riduce alle preferenze personali.

Anche rendere statica una class è più efficiente, se si dichiara una class interna anonima in un’istanza, ci sarà un sovraccarico maggiore, il che, se non si ha bisogno di accedere alle variabili di istanza, è dispendioso (ma probabilmente non vale la pena preoccuparsi di finché non si presenta come un problema).

La mia preferenza personale è quella di utilizzare classi non anonime in quanto consentono una maggiore flessibilità quando il codice viene modificato in seguito.

Perché hai bisogno di sottoclass? Se è solo per scavalcare un metodo virtuale esistente, penso che una class interiore anonima sia a posto. Se aggiungi funzionalità aggiuntive, utilizzerei una class con nome. Lo renderei comunque una class nidificata (cioè con il modificatore static ) – trovo che sia più facile ragionare 🙂

Fai la cosa più semplice che possa funzionare : usa la class interiore anonima.

Se in seguito si scopre che è necessario un ambito più ampio, quindi refactoring il codice per supportare questo.

(Si farebbe lo stesso con le variabili – inserendole nel campo di applicazione più specifico: ha senso fare lo stesso con altre risorse di origine).

Le classi interne anonime sono difficili da eseguire il debug in Eclipse (questo è quello che uso). Non sarai in grado di esaminare i valori delle variabili / iniettare i valori semplicemente facendo clic con il pulsante destro del mouse.

Uno svantaggio delle classi interne è che non possono essere statici. Ciò significa che manterrà un riferimento alla class esterna che li contiene.

Le classi interne non statiche possono essere un problema. Ad esempio, recentemente è stata serializzata una class interna, ma la class esterna non è serializzabile. Il riferimento nascosto significava che anche la class esterna sarebbe stata serializzata, il che ovviamente non ha funzionato, ma ci è voluto un po ‘per scoprire perché.

Dove lavoro, le classi interne statiche sono incoraggiate nelle nostre migliori pratiche di codifica (ove ansible) poiché trasportano meno bagaglio nascosto e sono più snelle.

La mia regola pratica personale: se la class interiore anonima sarà piccola, segui una class anonima. Piccolo definito come circa 20 – 30 linee o meno. Se sarà più lungo, a mio parere inizierà a essere illeggibile, quindi la classificherò come una class interiore. Ricordo di aver visto una class interiore anonima di oltre 4000 righe.

Le classi interne anonime sarebbero generalmente la strada da percorrere. Li trovo molto leggibili. Tuttavia, se l’istanza di quella class ha bisogno di essere serializzata (anche se solo perché è un campo di qualcos’altro), consiglio vivamente l’uso di classi interne con nome. I nomi delle classi interne anonime nel bytecode possono cambiare molto facilmente e questo può interrompere la serializzazione.

Le classi anonime non possono avere un costruttore, poiché non hanno un nome. Se è necessario passare altre variabili rispetto a quelle del costruttore o dei costruttori della class che si sta estendendo, è necessario utilizzare una class interna (statica) con nome. Questo a volte può essere superato usando le variabili finali nel metodo / codice circostante, ma è un po ‘brutto (e può portare a ciò che Robin ha detto).

Non ho problemi con semplici classi anonime. Ma se consiste di più di poche righe di codice o di un paio di metodi, una class interiore è più chiara. Penso anche che in determinate condizioni non dovrebbero mai essere usati. Ad esempio quando devono restituire i dati.

Ho visto il codice in cui viene utilizzata una matrice finale di 1 elemento per passare i dati da una chiamata a una class interna anonima. All’interno del metodo della class anon, il singolo elemento è impostato, quindi questo ‘risultato’ viene estratto una volta che il metodo è completo. Codice valido, ma brutto.

Classi anonime:

  • non può avere nulla di static nella definizione (class statica, campo statico, inizializzatore statico, ecc.)
  • i campi non possono essere ispezionati in Eclipse
  • non può essere usato come un tipo ( Foo$1 myFoo=new Foo$1(){int x=0;} non funziona)
  • non può essere localizzato usando il nome della class in Eclipse (la ricerca di Foo$1 non funziona per me)
  • non può essere riutilizzato

Tuttavia, le classi anonime possono avere un inizializzatore come {super.foo(finalVariable+this.bar);}

Le classi interne nominate non hanno queste limitazioni, ma anche se una è usata esclusivamente nel mezzo di una lunga procedura, la dichiarazione dovrà essere spostata alla successiva class indicata.

Personalmente preferisco le classi interne anonime se le restrizioni non si applicano perché:

  • So che qualsiasi campo aggiuntivo viene fatto riferimento solo nella definizione della class.
  • Eclipse può convertirli facilmente in classi annidate.
  • Non ho bisogno di copiare in variabili che voglio usare. Posso solo dichiararli definitivi e riferirli. Questo è particolarmente utile quando ho molti parametri.
  • Il codice che interagisce è vicino.

Penso che quello che hai fatto abbia perfettamente senso in questo caso e in entrambi i casi lo guardi, penso che tu stia davvero dividendo i capelli con questo particolare problema. Sono entrambi così simili e funzioneranno.

Penso che sia una questione di gusti. Preferisco usare le classi anonime per Functors . Ma nel tuo caso, userei una class interiore, dal momento che penso che starai impacchettando più di poche righe di codice, forse più di un semplice metodo. E sottolineerebbe il fatto che aggiunge funzionalità alla superclass, inserendola nella class, piuttosto che nascosta da qualche parte in un metodo. Inoltre, chissà, forse un giorno potresti aver bisogno della sottoclass in cui. Questo, ovviamente, dipende da quanto sai su come si evolverà il tuo software. Oltre a questo, basta lanciare una moneta. 🙂

Ho appena avuto questa discussione oggi con il mio collega e stavo scavando intorno per un’opinione popolare.

Sono d’accordo con TofuBeer. Se il tuo codice ha più di 2 righe, probabilmente non è un “one-off” e potrebbe essere riutilizzato un giorno. Se stai creando un modulo usando un pattern MVC, potresti avere 20 elementi controllabili su una pagina invece di ingombrare la vista con tonnellate di classi anonymouse (probabilmente la tua vista è stata creata usando un builder GUI e il codice è stato auto-assegnato modificando la fonte non è nemmeno un’opzione) è probabile che si nutrirà ogni elemento con un controller. È ansible nidificare le classi interne all’interno del controller per gestire ciascuna interfaccia di gestore / listener diversa richiesta dalla visualizzazione. Ciò organizza il codice molto bene, specialmente se si ha una convenzione per cui la class del gestore deve essere denominata utilizzando il nome dell’elemento della GUI (come backButtonHandler per un backButtonElement). Questo ha funzionato molto bene per noi e abbiamo scritto uno strumento di registrazione automatica (quando registri un controller su una vista, la vista cerca le classi interne usando il nome dell’elemento e le usa per un gestore su ogni elemento con nome). Ciò non sarebbe ansible con classi anonime e rende il controller molto più riciclabile.

TLDR: in caso di dubbio scrivi una named inner class. Non saprai mai se qualcuno vorrà riutilizzare il tuo codice un giorno (a meno che non si tratti di 2 righe, quindi ti chiederai “questo odore ha il codice?”). Il codice che è ben organizzato ha benefici molto più elevati a lungo termine, specialmente quando il tuo progetto è in manutenzione.

Con le classi interne anonime, non possiamo cambiare lo stato dei membri della class inclusi. Devono essere dichiarati come definitivi.