Per fare un esempio davvero stupido (anche più semplice del tuo), ci sono in realtà quattro pattern che potresti seguire:
Implementato separatamente
int AddNumbers(int a, int b)
{
return a + b;
}
int AddNumbers(int a, int b, int c)
{
return a + b + c;
}
Vantaggi: nessuna dipendenza, nessun ulteriore riferimento indiretto (molto leggero) miglioramento delle prestazioni
Contro: più lavoro da scrivere. Se trovi un bug, devi risolverlo in due punti.
Semplice prima
int AddNumbers(int a, int b)
{
return a + b;
}
int AddNumbers(int a, int b, int c)
{
return AddNumbers(a, b) + c;
}
Professionisti: se trovi un bug potresti essere in grado di risolverlo in un solo punto
Contro: un leggero colpo alle prestazioni che chiama la versione complessa. Le modifiche alla versione semplice potrebbero avere effetti collaterali non desiderati sulla versione complessa che potrebbero essere persi con il collaudo unitario ordinario che isolerebbe la versione semplice.
Complesso per primo
int AddNumbers(int a, int b, int c)
{
return a + b + c;
}
int AddNumbers(int a, int b)
{
return AddNumbers(a, b, 0);
}
O in alcune lingue potresti semplicemente scrivere
int AddNumbers(int a, int b, int c = 0)
{
return a + b + c;
}
Pro: una funzione sta facendo tutto il lavoro, la semplice funzione sostituisce semplicemente il valore predefinito. Testare la funzione semplice è banale.
Contro: leggero impatto sulle prestazioni. Possibile effetto collaterale creando un parametro predefinito, ad es. se la versione complessa accetta tipi complessi anziché primitivi (devi allocare il terzo parametro). Ma funziona alla grande con i tipi nullable.
Livelli
int AddNumbers(int a, int b, int c)
{
return AddNumbersInternal(new int[] {a, b, c});
}
int AddNumbers(int a, int b)
{
return AddNumbersInternal(new int[] {a, b});
}
private int AddNumbersInternal(int[] args)
{
int accumulator = 0;
foreach (int n in args) accumulator += n;
return accumulator;
}
Professionisti: cristallina cosa sta succedendo. Bug corretti in un unico posto. Consente la personalizzazione di ciascun prototipo senza influire sulla logica di base.
Contro: più lavoro.
Secondo me
Tutti gli approcci di cui sopra hanno il loro posto. Se quello che stai facendo è molto semplice, li implementerei separatamente, per essere onesti. se quello che stai facendo è molto complesso, implementerei usando l'approccio a strati.
Ma stai chiedendo i due approcci centrali. Li odio entrambi! Ma mi inclino a "complesso prima" dal momento che tutto il lavoro viene essenzialmente svolto in un unico posto, anche se si aggiungono sempre più prototipi che fanno cose diverse. Con l'approccio "semplice prima" stai dividendo la logica in due funzioni che possono confondere e dovrai dividerle sempre di più man mano che sono necessarie funzioni sempre più complesse.