Ho una classe che ha diversi campi che possono essere riempiti solo consecutivamente da un sacco di calcoli. Il 1 ° campo può essere impostato molto facilmente. Per riempire il secondo campo, prendiamo il contenuto del primo campo e calcoliamo molto. Il 3 °, 4 ° e 5 ° campo devono essere calcolati insieme da campo1 e campo2 (non è possibile calcolare 3, 4 e 5 isolati gli uni dagli altri senza gravi perdite di performance). E il sesto campo viene calcolato dal campo 1, 3 e 4.
Userò la sintassi C # per ogni esempio di codice.
class Foo
{
private Type1 f1; // obtained directly from input parameter of constructor
private Type2 f2; // from f1 we can calculate f2
private Type3 f3; // from f1 and f2 we can calculate the triple (f3,f4,f5)
private Type4 f4; // from f1 and f2 we can calculate the triple (f3,f4,f5)
private Type5 f5; // from f1 and f2 we can calculate the triple (f3,f4,f5)
private Type6 f6; // from f1, f3 and f4 we can calculate f6
public Foo(Type1 input)
{
... // What is a good way to write it?
}
}
Vorrei avere qualche input su un buon modo per implementare tale costruttore. Sono abbastanza nuovo nell'ingegneria del software della vita reale (ho appena realizzato alcuni progetti sandbox nell'università in precedenza) e non so ancora quali siano gli aspetti più importanti.
Ecco i due modi che ho in mente. Si prega di commentare su di loro, parlami di pro e contro non ho pensato, o dare esempi di come si dovrebbe scrivere un tale costruttore!
Prima versione: metodi statici senza effetti collaterali
public Foo(Type1 input)
{
f1 = input;
f2 = GetF2(f1);
Tuple<Type3, Type4, Type5> bar = GetF3F4F5(f1, f2);
f3 = bar.Item1;
f4 = bar.Item2;
f5 = bar.Item3;
f6 = GetF6(f1, f3, f4);
}
private static Type2 GetF2(Type1 field1)
{
Type2 field2 = new Type2();
... // calculating a lot, setting the correct value for field2
return field2;
}
private static Tuple<Type3, Type4, Type5> GetF3F4F5(Type1 field1, Type2 field2)
{
Type3 field3 = new Type3();
Type4 field4 = new Type4();
Type5 field5 = new Type5();
... // calculating a lot, setting the correct values for field3, 4 and 5
return new Tuple<Type3, Type4, Type5>(field3, field4, field5);
}
private static Type6(Type1 field1, Type3 field3, Type4 field4)
{
Type6 field6 = new Type6();
... // calculating a lot, setting the correct value for field6
return field6;
}
Pro:
- A ogni riga del costruttore, si sa esattamente quali campi sono già impostati e quali no, rendendolo chiaramente leggibile.
- I calcoli sono incapsulati in metodi free effect, rendendoli facilmente modificabili.
- Ogni metodo mostra chiaramente quali campi sono necessari per il calcolo.
con
- La creazione di tuple ha un sovraccarico.
- Potrebbe sembrare inutile per il lettore che una variabile sia definita, inizializzata e restituita solo per impostare un campo su questo valore, invece di impostare direttamente il campo.
Seconda versione: metodi non statici che manipolano direttamente i campi
public Foo(Type1 input)
{
f1 = input;
GetF2();
GetF3F4F5();
GetF6();
}
private void GetF2()
{
f2 = new Type2();
... // calculating a lot with f1, setting the correct value for f2
}
private void GetF3F4F5()
{
f3 = new Type3();
f4 = new Type4();
f5 = new Type5();
... // calculating a lot with f1 and f2, setting the correct values for f3, f4 and f5
}
private void Type6()
{
f6 = new Type6();
... // calculating a lot with f1, f3, f4, setting the correct value for f6
}
Pro:
- Leggermente più corto.
- Nessun sovraccarico della tupla.
- Probabilmente un po 'più veloce perché manca la deviazione "initialize- > return- > set". (solo una supposizione)
con
- Se prendi qualche riga nel costruttore, non puoi dire quali campi sono già inizializzati e quali no. (O forse puoi farlo a causa dei nomi dei metodi, ma per i miei occhi non è chiaro come nella prima versione.)
- I metodi non indicano quali campi usano per il calcolo.