2009-04-03 15 views
40

Ho una classe, chiamiamola LineGraph, che esegue il rendering di un grafico a linee. Devo creare una sottoclasse, ma la classe derivata è usata solo in un posto ed è accoppiata alla classe che lo usa. Quindi sto usando una classe interiore.Anonimo vs classi interne nominate? - migliori pratiche?

vedo due modi per farlo:

Anonymous classe interna

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

Chiamato classe interna

public class Gui { 
    MyLineGraph graph = new MyLineGraph(); 

    private class MyLineGraph extends LineGraph { 
     // extra functionality here. 
    } 
} 

io non sono un fan di classi interne anonime, perché francamente penso che sia davvero brutto. Ma nel caso di una sottoclasse che è usata solo in un posto, c'è un overkill di classe interna chiamato? Qual è la pratica accettata?

+5

Lambda's anyone :) – Matt

risposta

9

Perché è necessario sottoclasse? Se è solo per scavalcare un metodo virtuale esistente, penso che una classe interiore anonima sia a posto. Se aggiungi funzionalità aggiuntive, utilizzerei una classe con nome. Lo farei comunque con una classe nidificata (cioè con il modificatore static) - Trovo più facile ragionare :)

+0

Il mio esempio è stato un po 'semplificato. Nel codice reale, sostituisce 5 metodi (non astratti). –

+0

Sembra abbastanza da renderlo degno di essere trasformato in una classe con nome. Mi piacciono le mie classi anonime per essere piccole. –

+1

concordato. Di solito uso solo classi anonime se sono davvero semplici. Qualunque sia la definizione di una piccola funzione e la renderò una normale classe interna (se possibile statica). Semplicemente più facile da leggere in questo modo. – Herms

0

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.

+0

Ci sono molte volte in cui funzionano due opzioni, ma una è più leggibile e mantenibile rispetto a un'altra. Penso che abbia molto senso chiedere le opinioni di altre persone in caso di dubbi sul modo migliore di procedere. –

47

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

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

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

+3

+1 Punti buoni, ma ricorda che le classi possono essere definite anche all'interno delle funzioni. Questo limita la loro portata e può essere un buon indizio di avere un uso molto localizzato. –

+3

Questi sono ottimi motivi per non utilizzare classi anonime. :) –

0

Penso che sia una questione di gusti. Preferisco utilizzare le classi anonime per Functors. Ma nel tuo caso, userei una classe 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 superclasse, inserendola nella classe, piuttosto che nascosta da qualche parte in un metodo. Inoltre, chissà, forse un giorno potresti aver bisogno della sottoclasse in cui. Questo, ovviamente, dipende da quanto sai su come si evolverà il tuo software. Oltre a questo, basta lanciare una moneta. :)

4

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.

2

Le classi interne anonime sarebbero generalmente la strada da percorrere. Li trovo molto leggibili. Tuttavia, se l'istanza di quella classe 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.

36

(Counter punto a Daniel Lew)

Uno svantaggio delle classi interne anonime è che nessuno potrà mai utilizzarlo in qualsiasi altro luogo, mentre una classe interna di nome può essere utilizzato (anche se solo dalla classe che lo ha creato, se reso privato). È una piccola distinzione, ma significa che puoi contribuire ad assicurare che una classe interiore non venga ricreata casualmente altrove.

Inoltre, utilizzando la classe interna anonima dà chiunque legga il codice di un tempo più difficile perché poi devono analizzare questa classe che è venuto fuori dal nulla. Usando una classe interna chiamata puoi organizzare di più la sorgente.

Ho visto casi in cui ci sono due (o più) classi interne anonime con lo stesso codice esatto. 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).

La questione leggibilità va in entrambe le direzioni, alcune persone trovano classi interne anonime migliore in quanto consente di vedere ciò che sta accadendo in una volta posto, altri trovano una distrazione. Questa parte si riduce alle preferenze personali.

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

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

+3

Questo è quello che trovo brutto riguardo alle classi interne anonime. Stai leggendo il codice e all'improvviso c'è questa definizione di classe in mezzo a un mucchio di campi. –

+0

Ho sempre problemi nell'allineare il codice all'interno della classe anonima. Non importa quanto duramente provi, il codice sembra ancora brutto: D – janetsmith

+0

Sono d'accordo: trovo il codice difficile da leggere/debug se ci sono molte classi interne anonime. Invece di dichiarare classi interne anonime all'interno di più funzioni (YUCK!), Trovo che sia molto più pratico dedicare sezioni del file alle classi interne nominate, cioè la parte inferiore del file. –

3

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

Le classi interne non statiche possono costituire un problema. Ad esempio, recentemente è stata serializzata una classe interna, ma la classe esterna non è serializzabile. Il riferimento nascosto significava che anche la classe 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 best practice di codifica (ove possibile) poiché trasportano meno bagaglio nascosto e sono più snelle.

1

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

ho visto codice in cui una matrice finale di 1 voce è utilizzata per trasferire i dati di ritorno da una chiamata a una classe interna anonima. All'interno del metodo della classe anon, il singolo elemento è impostato, quindi questo 'risultato' viene estratto una volta che il metodo è completo. Codice valido, ma brutto.

7

Do the simplest thing that could possibly work: utilizzare la classe interna anonima.

Se successivamente si scopre che è necessario un ambito più ampio, quindi rifattorizzare il codice per supportarlo.

(si dovrebbe fare lo stesso con le variabili - di metterli nel campo di applicazione più specifica Ha senso fare lo stesso con le altre attività di origine..)

3

La mia regola personale empirica: Se la classe interna anonima sta per essere piccolo, seguire una classe anonima. Piccolo definito come circa 20 - 30 linee o meno. Se sta per essere più lungo, a mio avviso inizia a essere illeggibile, quindi ne faccio una classe interiore denominata. Ricordo di aver visto una classe interiore anonima di oltre 4000 righe.

2

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 classe che si sta estendendo, è necessario utilizzare una classe 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).

classi
1

anonimi:

  • non possono avere nulla static nella definizione (classe statica, campo statico, inizializzatore statico, etc.)
  • campi non possono essere ispezionate in Eclipse
  • non possono essere utilizzati come tipo (Foo$1 myFoo=new Foo$1(){int x=0;} non funziona)
  • non può essere individuato utilizzando il nome della classe in Eclipse (ricerca di Foo$1 non funziona per me)
  • ca nnot essere riutilizzati

Le classi anonime può, tuttavia, avere un inizializzatore come {super.foo(finalVariable+this.bar);}

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

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

  • So eventuali campi aggiuntivi si fa riferimento solo nella definizione di classe.
  • 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.
0

Ho appena avuto questa discussione oggi con il mio collega e stavo scovando per l'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. È possibile 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 classe 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 possibile con classi anonime e rende il controller molto più riciclabile.

TLDR: in caso di dubbio scrivere una classe interna con nome.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.

0

Con classi interne anonime, non è possibile modificare lo stato dei membri della classe inclusi. Devono essere dichiarati come definitivi.