2010-10-25 9 views
9

Qualsiasi opinione sul modo migliore di organizzare i membri di una classe (specialmente quando ce ne sono molti) in C++. In particolare, una classe ha molti parametri utente, ad es. una classe che ottimizza alcune funzioni e ha un numero di parametri come # di iterazioni, dimensioni della fase di ottimizzazione, metodo specifico da usare, pesi delle funzioni di ottimizzazione ecc. Ho provato diversi approcci generali e sembra trovare sempre qualcosa di non ideale con esso. Solo curiose altre esperienze.Best practice per una classe con molti membri

  1. struct all'interno della classe
  2. struct di fuori della classe
  3. variabili membro pubbliche
  4. variabili membro private con Set() e Get() Funzioni

essere più concreti, il codice Sto lavorando su oggetti traccia in una sequenza di immagini. Quindi un aspetto importante è che ha bisogno di preservare lo stato tra i frame (perché non ho solo creato un sacco di funzioni). Funzioni membro significative includono initTrack(), trackFromLastFrame(), isTrackValid(). E ci sono un sacco di parametri utente (ad esempio quanti punti per tenere traccia per oggetto rintracciato, quanto un punto può muoversi tra i fotogrammi, metodo di monitoraggio utilizzato etc etc)

+2

Cosa intendi per parametri di una classe? Membri? Parametri del modello? Qualcos'altro? –

+6

Se ha * che * molti membri della tua classe fanno troppo, refactoring il tuo codice. – GManNickG

+0

Parli di una classe, ma sembra che tu stia descrivendo una funzione. : -/ –

risposta

1

Tutto dipende:

  1. Un interno struct sarebbe utile solo se hai bisogno di organizzare MOLTO molti articoli. E se questo è il caso, dovresti riconsiderare il tuo design.
  2. Una struttura esterna sarebbe utile se sarà condivisa con altre istanze della stessa classe o di classi diverse. (Un modello, o una classe/struttura di oggetto dati potrebbe essere un buon esempio)
  3. È sempre consigliabile solo per il codice triviale, da buttare via.
  4. Questo è il modo standard di fare le cose, ma tutto dipende da come userete la classe.
2

se dovessi scegliere una delle quattro soluzioni elencate: classe privata all'interno di una classe.

in realtà: probabilmente si dispone di un codice duplicato che deve essere riutilizzato e la classe deve essere riorganizzata in parti più piccole, più logiche e riutilizzabili. come ha detto GMan: refactoring il tuo codice

0

Non vedo alcun beneficio per creare una struttura separata per contenere i parametri. La classe è già una struct - se fosse opportuno passare parametri da una struct, sarebbe anche opportuno rendere pubblici i membri della classe.

C'è un compromesso tra membri pubblici e funzioni Set/Get. I membri pubblici sono molto meno affidabili, ma espongono il funzionamento interno della classe. Se questo codice verrà chiamato dal codice che non sarà in grado di refactoring se si refactoring la classe, quasi certamente si desidera utilizzare Get e Set.

+0

Ho una classe chiamata GraphicsVertex e ho 5 membri variabili (puntatori). Quando viene eseguita la mia applicazione, crea circa 50 milioni di oggetti. Ora per ogni oggetto terrà 5 membri * 50 Mn di memoria. Come posso evitarlo. –

+0

@DigviJayPatil Non so se c'è un modo per evitarlo. E questo è completamente il modo sbagliato di chiedere. –

+0

Devo fare una domanda o è giusto chiedere nei commenti? –

1

Suoni come questo potrebbero essere un lavoro per un modello, il modo in cui hai descritto l'utilizzo.

template class FunctionOptimizer <typename FUNCTION, typename METHOD, 
    typename PARAMS> 

per esempio, dove PARAMS incapsula semplici parametri di ottimizzazione (# di iterazioni, ecc) e METHOD contiene il codice di ottimizzazione vero e proprio. FUNCTION descrive la funzione di base che si sta mirando per l'ottimizzazione.

Il punto principale non è che questo è il modo "migliore" per farlo, ma che se la tua classe è molto grande ci sono probabilmente astrazioni più piccole al suo interno che si prestano naturalmente al refactoring in una struttura meno monolitica.

Tuttavia, se si gestisce questo, non è necessario eseguire il refactoring in una sola volta: eseguirlo a pezzetti, iniziando in piccolo e assicurarsi che il codice funzioni ad ogni passaggio. Sarai sorpreso di quanto tu possa sentirti meglio sul codice.

0

Supponendo che le opzioni di configurazione si applicano solo a questa classe, utilizzano variabili private che vengono manipolate da funzioni pubbliche con nomi di funzioni significative. SetMaxInteriorAngle() è molto meglio di SetMIA() o SetParameter6(). Avere getter e setter consente di applicare regole di coerenza sulla configurazione e può essere utilizzato per compensare determinate quantità di modifiche nell'interfaccia di configurazione.

Se queste sono impostazioni generali, utilizzate da più di una classe, una classe esterna sarebbe la migliore, con membri privati ​​e funzioni appropriate.

I membri di dati pubblici sono in genere una cattiva idea, poiché espongono l'implementazione della classe e rendono impossibile avere una relazione garantita tra loro. Rimuoverli in una struttura interna separata non sembra utile, anche se li raggrupperei nell'elenco dei membri dei dati e li inserirò con i commenti.

3

Se la classe è GRANDE, poi la classe è BAD. Una classe dovrebbe rispettare lo Single Responsibility Principle, ad esempio: Una classe dovrebbe fare solo una cosa, ma dovrebbe farlo bene. (Beh, "solo una" cosa è estrema, ma dovrebbe avere un solo ruolo e deve essere implementata chiaramente).

quindi si crea classi che si arricchiscono con composizione con quelle a singolo ruolo poco classi, ognuno con un ruolo chiaro e semplice.

funzioni BIG BIG e le classi sono nido per insetti, e di incomprensione, e gli effetti collaterali indesiderati, (in particolare durante manutenzione), perché nessun uomo può imparare in minuti 700 righe di codice.

Così la politica per le classi è grande: refactoring, Composizione con piccole classi con i clienti destinati solo a fare ciò che hanno.

+3

Avere molti parametri non significa che la classe sia grande. La classe potrebbe fare una cosa, ma richiede molti parametri. –

+0

@Adrian McCarthy, ti risponderò solo una citazione: "Se la tua funzione richiede 10 parametri, probabilmente ne hai dimenticato uno". –

+0

ma sono d'accordo con te, purché svolga un ruolo preciso. –

3

In primo luogo, dividerei i membri in due gruppi: (1) quelli che sono solo per uso interno, (2) quelli che l'utente modificherà per controllare il comportamento della classe. Il primo set dovrebbe essere solo variabile membro privato.

Se il secondo set è di grandi dimensioni (o cresce e cambia perché si sta ancora facendo lo sviluppo attivo), è possibile inserirli in una classe o una struttura. La tua classe principale avrebbe quindi due metodi, GetTrackingParameters e SetTrackingParameters. Il costruttore stabilirà le impostazioni predefinite. L'utente può quindi chiamare GetTrackingParameters, apportare le modifiche e quindi chiamare SetTrackingParameters. Ora, quando aggiungi o rimuovi parametri, l'interfaccia rimane costante.

Se i parametri sono semplici e ortogonali, possono essere racchiusi in una struttura con membri pubblici ben denominati. Se ci sono vincoli che devono essere applicati, in particolare combinazioni, quindi implementerei i parametri come una classe con getter e setter per ogni parametro.

ObjectTracker tracker; // invokes constructor which gets default params 
TrackerParams params = tracker.GetTrackingParameters(); 
params.number_of_objects_to_track = 3; 
params.other_tracking_option = kHighestPrecision; 
tracker.SetTrackingParameters(params); 
// Now start tracking. 

Se successivamente si inventi un nuovo parametro, basta per dichiarare un nuovo membro nel TrackerParams e inizializzarlo nel costruttore di ObjectTracker.