Come determinare se utilizzare l'ereditarietà o no?

3
// Car states : START, RUN, STOP


// START ==> RUN ==> STOP ==> Write
// CarFromStartToStop() :
// Car is initailly at STOP phase. 
// We start the and car comes in RUN phase.
// Then at the end car comes in STOP phase.
// WriteCarResults() : 
// Writes car's current status. eg : oil status, odometer etc.

class Info1 {
public:
  void Run(){
    CarFromStartToStop();
    WriteCarResults();
  }

private:
  void CarFromStartTopStop(){
    // Its own impelementation of how car will run.
  }
  void WriteCarResults(){
    // Write car's current status for running from start to finish.
  }

  Car c;

};

// RUN ==> STOP ==> Write
// CarFromRuningToStop() :
// The car is in RUN phase.
// Then at the end car comes in STOP phase.
// WriteCarResults() : 
// Writes car's current status. eg : oil status, odometer etc.

class Info2 {
public:
  void Run(){
    CarFromRuningToStop();
    WriteCarResults();
  }

private:
  void CarFromRuningToStop(){
    // Its own impelementation of how car will run.
  }
  void WriteCarResults(){
    // Write car's current status for running from start to finish.
  }

  Car c;

};

Ho queste due classi. A prima vista direi che potremmo usare l'ereditarietà. Loro più di meno fanno la stessa cosa. Corrono l'auto e scrivono i dati. Ma quando guardo da vicino, non sono sicuro se l'eredità è una buona scelta.

Perché?

Poiché l'unico metodo comune (utilizzare lo stesso codice esatto) tra due classi è WriteCarResults. Altro quindi che non esiste un codice comune.

La mia domanda: come posso assicurarmi di non dover scrivere il codice che è comune tra la classe (WriteCarResults).

Opzioni:

  1. Utilizza l'ereditarietà (per qualche motivo ritengo che questo approccio sia davvero artificiosa).

  2. Estrai la funzione writeCarResults () dalla classe. (Mi piace questo approccio, ma non sono sicuro se questo è buono. Un altro problema che sento con questo approccio WriteCarResults () dovrebbe essere parte delle informazioni * classe).

Per favore fatemi sapere se esiste un design che non mi permetta di scrivere la funzione writeCarResults () due volte.

    
posta mato 02.04.2018 - 03:07
fonte

2 risposte

13

Che ci crediate o no, ciò che veramente ostacola il tuo design sono i nomi.

Info1 e Info2 sono terribilmente prive di significato, Run() ruba il suo nome da una delle fasi dell'auto e copre tutte le fasi e altro, e la cosa peggiore di tutte CarFromStartToStop() e CarFromRunningToStop() entrambi i dettagli dell'implementazione di perdita che rendono il polimorfismo imposibile, se usi l'ereditarietà o meno.

Un nome dovrebbe trasmettere intenti. Dovrebbe garantire che ciò che si trova all'interno non sia una sorpresa. Ma non dovrebbe dirti come . Se dice come allora l'implementazione non può cambiare. Polymorphism significa che l'implementazione può cambiare. Ecco cosa succede quando segui questi principi di denominazione:

class StartToStopSimulator {
public:
  void Simulate(){
    OperateCar();
    WriteCarResults();
  }

private:
  void OperateCar(){
    c.Start();
    c.Run();
    c.Stop();
  }
  void WriteCarResults(){
    c.Status(outputPort);
  }

  Car c;

};

class RunningToStopSimulator {
public:
  void Simulate(){
    OperateCar();
    WriteCarResults();
  }

private:
  void OperateCar(){
    c.Run();
    c.Stop();
  }
  void WriteCarResults(){
    c.Status(outputPort);
  }

  Car c;

};

Con questi nuovi nomi siamo pronti a refactoring per utilizzare il polimorfismo.

class Simulator {
public:
  void Simulate(){
    OperateCar();
    WriteCarResults();
  }

private:
  void OperateCar(){
    operator.Operate(c);
  }
  void WriteCarResults(){
    c.Status(outputPort);
  }

  Car c;
  Operator operator;
  Output outputPort;
};

E lo costruiresti in questo modo:

Simulator sim = 
  new Simulator( 
    new CarCamaro(), 
    new OperatorSRS(), 
    new OutputConsole() 
  )
;

Ora l'operatore utilizzato decide quali misure dovrebbero essere prese per far funzionare la macchina. Le due classi Operator saranno diverse dalle classi precedenti in quanto si concentreranno SOLO sulle fasi.

Questo è un polimorfismo attraverso la composizione e la delega, ma potresti aver usato l'ereditarietà qui se lo avresti voluto. La composizione di solito si rivela più flessibile. Richiede solo un po 'più di digitazione della tastiera.

    
risposta data 02.04.2018 - 04:08
fonte
3

Che cosa dice CandiedOrange.

Un'altra osservazione: tutte le possibili ragioni che hai menzionato per l'utilizzo dell'ereditarietà sono sbagliate. Non usi l'ereditarietà per evitare la duplicazione del codice (che è solo una conseguenza naturale), usi l'ereditarietà quando vedi una relazione is-a.

Info2 è un (tipo di) Info1? È difficile da dire. La tua logica sembra essere tutta una questione di macchine, ma non vedo una classe di auto. Per quanto riguarda l'avvio e l'arresto, logicamente, è importante che tipo di auto hai a che fare? Qual è il risultato di una macchina? È uno stato di movimento? Non capisco molto della funzionalità prevista guardando le tue lezioni. Questo è ciò che una classe dovrebbe fornire, prima di tutto. Un estraneo con una mente vuota dovrebbe capire cosa significa. Se lo aggiusti prima, il resto sarà più semplice.

    
risposta data 02.04.2018 - 11:11
fonte

Leggi altre domande sui tag