sfondo
Sto lavorando a un progetto C # in corso. Non sono un programmatore C #, principalmente un programmatore C ++. Quindi mi hanno assegnato compiti sostanzialmente semplici e di refactoring.
Il codice è un casino. È un grande progetto. Poiché i nostri clienti richiedevano rilasci frequenti con nuove funzionalità e correzioni di bug, tutti gli altri sviluppatori sono stati costretti ad 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 sto eseguendo il refactoring, mi chiedo se lo sto facendo nel modo giusto poiché il mio codice refactored sembra complesso! Ecco il mio compito come semplice esempio.
Problema
Ci sono 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 è A::ExecJob()
stato scritto. Quindi è stata richiesta una versione leggermente diversa che è stata implementata in B::ExecJob()
copia-incolla-modifica di A::ExecJob()
. Quando è stata richiesta un'altra versione leggermente diversa, è C::ExecJob()
stata scritta e così via. Tutte e sei le implementazioni hanno un codice comune, quindi alcune righe 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;
}
Dov'è SN
un gruppo di stesse identiche dichiarazioni.
Per renderli comuni, ho creato un'altra classe e 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);
}
Si noti che in questo esempio vengono utilizzate solo tre classi e istruzioni semplificate. In pratica, la CommonTask()
funzione sembra molto complessa con tutti quei parametri che controllano e ci sono molte più istruzioni. Inoltre, nel codice reale, ci sono diverse CommonTask()
funzioni dall'aspetto.
Sebbene tutte le implementazioni condividano codice comune e le ExecJob()
funzioni siano più carine, esistono due problemi che mi danno fastidio:
- Per qualsiasi modifica
CommonTask()
, sono necessarie tutte e sei le funzionalità (e potrebbero essere più in futuro) da testare. CommonTask()
è già complesso. Diventerà più complesso nel tempo.
Lo sto facendo nel modo giusto?