Quando dovresti usare una classe privata / interiore?

19

Per chiarire, quello che sto chiedendo è

public class A{
    private/*or public*/ B b;
}

vs.

public class A{
    private/*or public*/ class B{
        ....
    }
}

Posso sicuramente pensare ad alcuni motivi per usare l'uno o l'altro, ma quello che mi piacerebbe davvero vedere sono esempi convincenti che dimostrano che i pro ei contro non sono solo accademici.

    
posta EpsilonVector 04.06.2011 - 09:06
fonte

9 risposte

18

In genere vengono utilizzati quando una classe è un dettaglio di implementazione interna di un'altra classe piuttosto che una parte della sua interfaccia esterna. Li ho visti per lo più come classi di soli dati che rendono le strutture di dati interne più pulite in linguaggi che non hanno una sintassi separata per le strutture in stile c. Sono anche utili a volte per oggetti derivati personalizzati con un solo metodo come gestori di eventi o thread di lavoro.

    
risposta data 04.06.2011 - 19:20
fonte
7

Supponiamo che tu stia costruendo un albero, una lista, un grafico e così via. Perché dovresti esporre i dettagli interni di un nodo o di una cella al mondo esterno?

Chiunque usi un grafico o una lista dovrebbe fare affidamento solo sulla sua interfaccia, non sulla sua implementazione, dal momento che potresti volere cambiarla un giorno nel futuro (ad esempio da un'implementazione basata su array a una basata su puntatori) e i client che utilizzano la struttura dei dati ( ognuno di essi ) dovrebbero modificare il loro codice per adeguarlo alla nuova implementazione.

Invece, incapsulare l'implementazione di un nodo o di una cella in una classe interna privata ti dà la libertà di modificare l'implementazione ogni volta che ne hai bisogno, senza che i client siano obbligati a modificare il loro codice di conseguenza, purché i tuoi dati l'interfaccia della struttura rimane intatta.

Nascondere i dettagli dell'implementazione della struttura dati comporta anche vantaggi in termini di sicurezza, perché se si desidera distribuire la classe si renderà disponibile solo il file di interfaccia insieme al file di implementazione compilato e nessuno saprà se si sta effettivamente utilizzando array o puntatori per la tua implementazione, proteggendo così la tua applicazione da qualche tipo di sfruttamento o, almeno, conoscenza dovuta all'impossibilità di usare impropriamente o ispezionare il tuo codice. Oltre ai problemi pratici, non sottovalutare il fatto che sia una soluzione estremamente elegante in questi casi.

    
risposta data 11.09.2012 - 09:32
fonte
5

Secondo me è un buon poliziotto usare classi definite internamente per classi che sono usate brevemente in una classe per consentire un'attività specifica.

Ad esempio, se è necessario associare un elenco di dati costituito da due classi non correlate:

public class UiLayer
{
    public BindLists(List<A> as, List<B> bs)
    {
        var list = as.ZipWith(bs, (x, y) => new LayerListItem { AnA = x, AB = y});
        // do stuff with your new list.
    }

    private class LayerListItem
    {
        public A AnA;
        public B AB;
    }
}

Se la tua classe interna è usata da un'altra classe, dovresti metterla separata. Se la tua classe interna contiene una logica, dovresti metterla separata.

Fondamentalmente, penso che siano ottimi per collegare buchi nei tuoi oggetti dati, ma sono difficili da mantenere se devono contenere effettivamente la logica, dal momento che dovrai sapere dove cercarli se hai bisogno di cambialo.

    
risposta data 04.06.2011 - 19:55
fonte
4
  • Le classi interne in una lingua (Java per esempio) hanno un legame con un oggetto della loro classe contenente e possono usare i loro membri senza qualificarle. Quando è disponibile, è più chiaro che reimplementarli utilizzando altre risorse linguistiche.

  • Le classi annidate in altre lingue (per esempio C ++) non hanno questo legame. Stai semplicemente utilizzando il controllo dell'ambito e dell'accessibilità fornito dalla classe.

risposta data 04.06.2011 - 10:42
fonte
3

Evito le classi interne in Java perché lo swapping a caldo non funziona in presenza di classi interne. Odio questo perché odio davvero compromettere il codice per tali considerazioni, ma quelle di Tomcat si riavviano.

    
risposta data 05.06.2011 - 02:37
fonte
2

Uno degli usi per la classe interna statica privata è il pattern Memo. Metti tutti i dati che devono essere ricordati nella classe privata e restituiscili da qualche funzione come Oggetto. Nessuno al di fuori non può (senza riflessione, deserializzazione, controllo della memoria ...) esaminarlo / modificarlo, ma può restituirlo alla classe e ripristinare il suo stato.

    
risposta data 11.09.2012 - 09:28
fonte
2

Un motivo per utilizzare una classe interna privata potrebbe essere dovuto al fatto che un'API che stai utilizzando richiede l'ereditarietà da una particolare classe, ma non vuoi esportare la conoscenza di quella classe agli utenti della tua classe esterna. Ad esempio:

// async_op.h -- someone else's api.
struct callback
{
    virtual ~callback(){}
    virtual void fire() = 0;
};

void do_my_async_op(callback *p);



// caller.cpp -- my api
class caller
{
private :
    struct caller_inner : callback
    {
        caller_inner(caller &self) : self_(self) {}
        void fire() { self_.do_callback(); }
        caller &self_;
    };

    void do_callback()
    {
        // Real callback
    }

    caller_inner inner_;

public :
    caller() : inner_(*this) {}

    void do_op()
    {
        do_my_async_op(&inner_);
    }
};

In questo, do_my_async_op richiede un oggetto di tipo callback da passarvi. Questa callback ha una firma di funzione membro pubblica che l'API utilizza.

Quando do_op () viene chiamato da outer_class, utilizza un'istanza della classe interna privata che eredita dalla classe callback richiesta invece di un puntatore a se stesso. La classe esterna ha un riferimento alla classe esterna per il semplice scopo di smistare il callback nella funzione membro private do_callback della classe esterna.

Il vantaggio di questo è che sei sicuro che nessun altro possa chiamare la funzione membro "fire ()" pubblica.

    
risposta data 11.09.2012 - 13:47
fonte
2

Secondo Jon Skeet in C # in Depth, l'uso di una classe nidificata era l'unico modo per implementare completamente pigro thread-safe singleton (vedere la quinta versione) (fino a .NET 4).

    
risposta data 11.09.2012 - 22:39
fonte
1

Le classi private e interne vengono utilizzate per aumentare i livelli di incapsulamento e nascondere i dettagli di implementazione.

In C ++, oltre a una classe privata, lo stesso concetto può essere ottenuto implementando uno spazio dei nomi anonimo di classe cpp. Questo è utile per nascondere / privatizzare un dettaglio di implementazione.

È la stessa idea di una classe interna o privata, ma a un livello ancora più grande di incapsulamento poiché è completamente invisibile al di fuori dell'unità di compilazione del file. Nulla di ciò appare nel file di intestazione o è visibile esternamente nella dichiarazione della classe.

    
risposta data 11.09.2012 - 04:27
fonte

Leggi altre domande sui tag