Progetta una classe che contiene informazioni di analisi

3

Diciamo che possiedo un ristorante che fa una torta. Voglio tagliare questa torta in base all'input analizzato dal file. Questo contiene la chiave per le informazioni su come tagliare la torta. Io uso CircleDividerParser class per analizzare file.txt.

formato di file:

  • pie_cuttin_style_name = è la chiave per la ricerca indietro
  • raggio = raggio o torta
  • x = coordinata x del centro della torta
  • y = coordinata y del centro della torta
  • angle_type = l'angolo può essere in gradi o in radianti
  • angle_value = valore dell'angolo che può essere radiante o gradi
  • direction = in senso orario o antiorario
  • from_x = x punto in circolo da dove l'angolo è misurato
  • from_y = y punto in circonferenza da dove si trova l'angolo misurata

ad esempio: file.txt

cutting_pattern_1,5,1,2,degree,40,anti-clock,6,2

....

..

Allora ho una classe per fare la logica di analisi:

Class CircleDividerParser{

  // does the parsing logic to capture the values
  void Dowork(filename){
    std::ifstream file_stream.open(filename);
    std::string line;
    while(std::getline(file_stream, line){
       std::string str;
       std::stringstream ss(line);
       int i = 0;
       while(std::getline(ss, str, ',')){
         holder[i] = str; 
         i++;
       }
       pcc.add_pie_cutting_info(holder);
    }

  }

  private:
   std::array<std::string, 9> holder;
   PieCutterCreator pcc;

};

// Questa classe esegue la creazione di PieCuttingInfo in base alla matrice di stringa fornita da CicleDividerParser

class PieCutterCreator{

public:
  void add_pie_cutting_info(std::array<std::string, 9> arr){
     PieCuttingInfo obj;    

     obj.AddPieCuttingStyleName(arr[0]);
     obj.AddRadius(arr[1]);
     ...
     ..

  }
  PieCuttingInfo GetPieCuttingInfo(const std::string& name_to_find);

  std::vector<PieCuttingInfo> GetAllPieCuttingInfo() { return collect;}

private:
  std::vector<PieCuttingInfo> collect;

};

class PieCuttingInfo{

  class enum angle_type {Degree, Radian};

public:
  PieCuttingInfo()=default;

  void AddPieCuttingStyleName(const std::string& name){ pie_cutting_style_name = name;}

  void AddRaius(const std::string& r) {radius = r;}

  void AddAngleType(const std::string& at) {
    if(at == "degree"){
      angle_value = angle_type::Degree;
    }else if(at == "radian"){
      angle_value = angle_type::Radian;
    }else {// error}
  }
   ...


private:

 std::string pie_cutting_style_name;
 std::string radius;// radius or pie 
 std::string x;//  x-coordinate of pie center
 std::string y;//  y-coordinate of pie center
 std::string angle_type;  angle can be either degree or radian
 std::string angle_value; value of angle that could be radian or degree
 std::string direction;  clock wise or anti-clockwise angle
 std::string from_x;   x point in circle from where the angle is measured
 std::string from_y;   y point in circle from where the angle is measured

};


class PieCuttingMaching(){

  void DoAllThePieCutting(){
    save = obj.GetAllPieCuttingInfo();
    for(auto& it: save){
        // use the info from PieCuttingInfo to do the job
    }
  }  

private:
  std::vector<PieCuttingInfo> save;
  PieCutterCreator obj;
}

Domande:

  • Il design che sto seguendo è corretto o sto creando delle cose compilcated
  • È possibile creare una classe PieCuttingInfo anche se tutte le informazioni lo sono non fornito.
  • Le variabili della classe PieCuttingInfo devono essere inizializzate durante la sua creazione da  passando tutte le variabili contemporaneamente.
posta vanta mula 24.10.2017 - 04:13
fonte

1 risposta

3

Bene, ciò che vedi prima veramente fornello per alimenti per la colazione . A parte gli scherzi, sembra che la tua soluzione stia dando spazio a errori nel tuo file letto, e il tuo programma avrebbe difficoltà a determinare potenziali errori di questo tipo. Non posso dirlo perché forse la macchina che affetta le torte ha bisogno di tutte queste informazioni e tu vuoi dare il massimo controllo alla persona che scrive il file.

Non c'è niente di sbagliato in questo, di per sé, ma è un livello molto basso. Vale a dire, la persona che scrive i parametri deve avere tutto a posto, non tu. Se questo è stato inserito in una macchina, c'è una seria possibilità che la macchina faccia cose che non può fare o tenta di fare e finisce per distruggere se stessa nel processo.

La semplificazione è la chiave

Questi possono essere i parametri effettivi della macchina, ma il mio consiglio è di semplificare le operazioni di taglio della torta in casi d'uso e tradurre i parametri "semplici" in quelli più complessi che la macchina può eseguire. Inizia con una classe astratta CuttingInfo con il metodo GetMachineParams . Qualsiasi classe derivante da CuttingInfo prende come input parametri semplificati e il suo output a GetMachineParams sono i dettagli di basso livello da passare alla macchina.

Puoi anche creare una classe astratta Parser con metodi CanRead e Read . CanRead può essere chiamato con la riga corrente del file per determinare se può essere deserializzato da quella classe, e Read viene quindi chiamato quando CanRead restituisce true che restituisce un'istanza di CuttingInfo .

Usa caso - 8 sezioni

Voglio che la macchina divida la mia torta in 8 fette pari. Questa sarà una richiesta popolare senza dubbio. Se non sono 8 fette, quindi 10 o 6, ma comunque l'utente del programma, ovvero il tuo cliente, non parlerà del numero di radianti per fetta o del movimento in senso antiorario.

La classe NEvenSlicesCuttingInfo prende come parametro solo un numero che presenta N. Il lavoro effettivo di tradurre questo in una serie di istruzioni, va in GetMachineParams .

Hai quindi solo bisogno di una classe NEvenSlicesParser che restituisce true su CanRead se e solo se la riga inizia con "NEvenSlices". Il secondo parametro sulla stessa riga deve essere N. Quindi la riga nel file deve essere:

NEvenSlices 8

Il lavoro di NEvenSlicesParser in Read non dovrebbe essere più sofisticato di leggere il parametro dopo NEvenSlices e restituire un new NEvenSlicesCuttingInfo(numberRead) .

Certo, il file potrebbe ancora contenere parametri impropri in questo modo, ma è possibile controllare i parametri semplificati. Supponendo che la tua classe faccia come dovrebbe, non devi preoccuparti di rompere la macchina con questi parametri.

Unendolo insieme

Per utilizzarlo, nel tuo programma avresti un vettore di Parser classi istanziate una volta all'avvio del programma con tutte le implementazioni di Parser . Mentre leggi il file, riga per riga, passi a CanRead . Se restituisce true, chiama il suo metodo Read e riceve un CuttingInfo che puoi chiamare in qualsiasi momento per recuperare i parametri della macchina. Tutto questo senza conoscere i dettagli di implementazione in ogni classe di implementazione.

Puoi vedere chiaramente che puoi ampliarlo per aggiungere altri casi d'uso. Puoi persino coprire il tuo scenario originale creando un parser 1 a 1 che carica ogni parametro possibile e lo restituisce semplicemente in GetMachineParams se richiedi il controllo assoluto che non interrompa questo pattern se richiesto (anche se sconsiglio strongmente uso di tale classe).

Questo approccio ha lo svantaggio di dover riscrivere il file di istruzioni per contenere tutte le informazioni sulla stessa linea, ma nulla ti impedisce di creare un parser più sofisticato che abbia una sorta di convenzione per scrivere istruzioni su più righe (es. se vedi la riga iniziare con <<< , leggi finché non trovi la riga che termina con >>> e restituisci il contenuto nel mezzo a Parser.CanRead ).

La cosa fondamentale è che alla logica del tuo programma non interessano più i dettagli di implementazione, consentendo la massima flessibilità e una facile manutenzione futura.

    
risposta data 24.10.2017 - 09:16
fonte

Leggi altre domande sui tag