Progettare classi per prevenire future interruzioni di codice

2

Mi piacerebbe progettare una versione robusta di questa classe (C ++ 11):

class Oscillator
{
  private:
    std::vector<double> trajectory_;
    // Some numbers that are needed to get the trajectory
    double xinit_;
    double vinit_;
    double omega_;
  public:
    Oscillator(double xinit, double vinit, double omega): 
      xinit_(xinit), vinit_(vinit), omega_(omega) {}

    void Integrate(); // Implementation populates 'trajectory_'
    // Implementation prints the trajectory in JSON-friendly format
    void PrintJSON(std::ostream &);
    double TrajectoryMean();
    double TrajectoryStdv();
};

Ecco alcuni pensieri:

  1. Vorrei sostituire il metodo PrintJSON con una variabile privata di classe TrajectoryPrinter o qualcosa, in modo che non debba cambiare Oscillator::PrintJSON e ricompilare oscillator.cpp ogni volta che si verifica un problema
  2. Lo stesso vale per il membro TrajectoryMean . Preferirei avere una classe TrajectoryStats che faccia questo per me.

L'unico problema con i punti precedenti è questo: entrambe le classi proposte richiedono l'accesso a un membro privato di Oscillator : trajectory_ .

Esiste un modello di progettazione o una soluzione di progettazione generica per questo problema? È quello che sto chiedendo possibile?

Grazie.

    
posta Salmonstrikes 20.07.2016 - 04:08
fonte

2 risposte

7

Se vuoi che TrajectoryPrinter chieda un TrajectoryPrinter . In questo momento stai solo chiedendo il doppio.

Qualcosa dovrà creare Oscillator . Qualcosa dovrà creare TrajectoryPrinter . Non consiglio che Oscillator compili o trovi anche TrajectoryPrinter . Oscillator non dovrebbe sapere TrajectoryPrinter come nulla tranne che come qualcosa che può chiamare una funzione print() attiva.

TrajectoryPrinter è una dipendenza. Ne hai bisogno. Proprio come hai bisogno di xinit , vinit e omega . Quindi lascia che sia qualcuno a consegnarteli tutti.

Puoi farlo in main ma lo fai in main molto e diventa affollato. Va bene creare classi il cui unico compito è creare altre classi.

Si chiama semplicemente passaggio ma alcune persone lo chiamano iniezione dipendenza . La differenza è principalmente se stanno cercando di venderti un framework.

    
risposta data 20.07.2016 - 04:44
fonte
1

Se la funzione integrata viene invocata una sola volta per oggetto, quello che hai è un costruttore di traiettorie, solo che non espone la traiettoria come un'entità di prima classe.

Quindi, potresti creare una nozione di prima classe del concetto di traiettoria e avere la tua funzione di integrazione come costruttore per costruire l'entità della traiettoria.

Una volta che hai un'entità di traiettoria di prima classe, puoi passarla a vari altri metodi, come serializzatori e altri manipolatori.

    
risposta data 20.07.2016 - 16:54
fonte

Leggi altre domande sui tag