Quando la sottoclasse è meglio "Copia Incolla, quindi Refactor", o "Refactor, quindi Implementa"

1

Al momento ho una classe Foo , ho deciso che ho bisogno di un secondo tipo di Foo in cui voglio testare un'implementazione significativamente diversa. Senza dubbio condividerò alcune funzionalità con Foo quindi dovrò creare un genitore di Classe astratta per entrambi.

Alla fine del processo voglio:

  • AbstractFoo : una classe astratta
  • FooBoo : funzionale identico all'originale Foo
  • FooBar : la nuova sottoclasse di AbstractFoo che ho creato.

Ci sono due modi in cui potrei fare questo:

Copia Incolla, quindi Rifattore

  1. Crea una copia di Foo e assegnagli il nome FooBar e rinomina Foo in FooBoo
  2. Modifica FooBar con la nuova implementazione
  3. Ispeziona, FooBar e FooBoo , sposta i metodi che sono uguali tra loro in una classe astratta AbstractFoo , che entrambi ereditano da

Refactor, quindi Implement

  1. Rinomina Foo , FooBoo
  2. Considera quali metodi non sono correlati alla parte dell'implementazione in cui FooBoo e FooBaz saranno diversi. Spostali a AbstractFoo
  3. Crea FooBaz e reimplementa tutti i metodi che rimangono all'interno di FooBoo

Quale è preferibile? * Esiste un altro metodo? *

L'ultima volta che ho dovuto fare questo, è stato perché ho deciso che Foo aveva 2 diverse modalità, che era determinata da un booleano passato al costruttore.

Questa volta (in una classe diversa), è perché voglio provare a utilizzare un motore diverso sotto che potrebbe essere più veloce. Voglio mantenere FooBoo in giro perché ha una sottoclasse che penso sarà molto più difficile da implementare per FooBaz , e voglio anche essere in grado di verificare che alla fine si comportino allo stesso modo.

    
posta Lyndon White 08.02.2014 - 11:29
fonte

3 risposte

1

Difficile dire, dipende dal caso, quale approccio ha più senso.

Se la maggior parte della roba sta entrando nella classe base, utilizzerei il tuo approccio " Refactor, quindi Implement " o seguirò una variante leggermente modificata dell'approccio @Euphorics : farei in modo che tutto funzioni come prima dopo il suo Passaggio 3 (completato AbstractFoo e FooFoo ) e prima passando al suo Passaggio 4 (creando FooBar ).

In alcuni casi, è al contrario . Decidi per una classe base comune, che in realtà avrà solo pochi metodi dal vecchio Foo . In tal caso, rinomina Foo in FooFoo , crea un AbstractFoo vuoto e sposta i pochi metodi nella nuova base (non dimenticare di modificare l'ereditarietà di FooFoo s).

Ho anche utilizzato l'approccio " copia + incolla + refactor ". Può essere utile, quando i metodi per passare alla base rispetto ai metodi che devono rimanere in FooBoo sono intorno alla distribuzione 50:50. Di nuovo, dipende, e a volte troverai durante il refactoring, che hai bisogno di un'altra classe per estrarre le cose dalla famiglia di classi Foo .

    
risposta data 08.02.2014 - 12:52
fonte
1

Vado con l'approccio copy + paste come antipasto, che ti dà la flessibilità di fare tutto ciò che vuoi con la nuova classe senza apportare effetti collaterali non voluti nel codice esistente. Questo sarebbe un po 'caduto sotto il modello di "applicazione di tracciamento" dal momento che l'intento principale è provare un motore completamente nuovo.

Quando ottieni il / i risultato / i riuscito / i dalla tua copia + codice incollato seguirai il modello guidato dal test e rifattorri i bit comuni nella tua classe base astratta ecc. Ciò si avvicinerebbe a quanto discusso nel Kent Becks Test -Driven Development con l'esempio, nonché i modelli di lavoro comuni discussi nel programmatore pragmatico.

IMHO quanto sopra è il modo in cui affronterò questo problema il più delle volte poiché lascia spazio a sperimentazioni folli pazzesche senza influenzare il codice già funzionante e testato con il minimo sforzo (ad esempio, nessun test corrente verrà modificato o rotto ecc. e la logica rimane intatta). Il grande sforzo viene quando hai il tuo tracciante funzionante per buttarlo via e scrivere un'implementazione pulita basata sul tuo codice di tracciamento o per iniziare a integrarlo con il tuo codice reale.

    
risposta data 08.02.2014 - 17:22
fonte
0

Lo farei in questo modo:

  1. Rinomina Foo in AbstractFoo e rendilo astratto
  2. Crea FooBoo che deriva da AbstractFoo
  3. Spingi tutti i metodi da AbstractFoo a FooBoo lasciando solo i metodi astratti
  4. Implementa FooBar

Mi piace perché la maggior parte di essa può essere raggiunta usando le funzioni refactor di IDE. Ciò garantisce che non sia necessario modificare manualmente il codice in cui è stato utilizzato Foo . Inoltre, il compilatore ti dà errori nelle posizioni in cui hai utilizzato il costruttore di Foo , perché non può istanziare una classe astratta.

    
risposta data 08.02.2014 - 12:07
fonte

Leggi altre domande sui tag