Sfondo
Sto lavorando a un progetto C # in corso. Non sono un programmatore C #, principalmente un programmatore C ++. Quindi mi è stato assegnato fondamentalmente compiti facili e di refactoring.
Il codice è un casino. È un grande progetto. Poiché i nostri clienti richiedevano versioni frequenti con nuove funzionalità e correzioni di bug, tutti gli altri sviluppatori erano costretti a adottare un approccio a forza bruta durante la codifica. Il codice è altamente non mantenibile e tutti gli altri sviluppatori sono d'accordo.
Non sono qui per discutere se hanno fatto bene. Mentre eseguo il refactoring, mi chiedo se lo sto facendo nel modo giusto, dal momento che il mio codice refactored sembra complesso! Ecco il mio compito come semplice esempio.
problema
Esistono sei classi: A
, B
, C
, D
, E
e F
. Tutte le classi hanno una funzione ExecJob()
. Tutte e sei le implementazioni sono molto simili. Fondamentalmente, all'inizio è stato scritto A::ExecJob()
. Quindi è stata richiesta una versione leggermente diversa implementata in B::ExecJob()
da copia-incolla-modifica di A::ExecJob()
. Quando è stata richiesta un'altra versione leggermente diversa, C::ExecJob()
è stato scritto e così via. Tutte e sei le implementazioni hanno un codice comune, quindi alcune linee di codice diverse, quindi ancora un codice comune e così via. Ecco un semplice esempio delle implementazioni:
A::ExecJob()
{
S1;
S2;
S3;
S4;
S5;
}
B::ExecJob()
{
S1;
S3;
S4;
S5;
}
C::ExecJob()
{
S1;
S3;
S4;
}
Dove SN
è un gruppo di esatte stesse affermazioni.
Per renderli comuni, ho creato un'altra classe e ho spostato il codice comune in una funzione. Utilizzo del parametro per controllare quale gruppo di istruzioni deve essere eseguito:
Base::CommonTask(param)
{
S1;
if (param.s2) S2;
S3;
S4;
if (param.s5) S5;
}
A::ExecJob() // A inherits Base
{
param.s2 = true;
param.s5 = true;
CommonTask(param);
}
B::ExecJob() // B inherits Base
{
param.s2 = false;
param.s5 = true;
CommonTask(param);
}
C::ExecJob() // C inherits Base
{
param.s2 = false;
param.s5 = false;
CommonTask(param);
}
Nota che questo esempio utilizza solo tre classi e istruzioni troppo semplificate. In pratica, la funzione CommonTask()
sembra molto complessa con tutti quei parametri di controllo e ci sono molte altre affermazioni. Inoltre, nel codice reale ci sono diverse funzioni di CommonTask()
-looking.
Sebbene tutte le implementazioni stiano condividendo il codice comune e le funzioni ExecJob()
guardino al cuter, esistono due problemi che mi infastidiscono:
- Per qualsiasi modifica in
CommonTask()
, tutte le sei (e potrebbe essere più in futuro) sono necessarie per essere testate. -
CommonTask()
è già complesso. Diventerà più complesso nel tempo.
Lo sto facendo nel modo giusto?