Monday, October 5, 2009

Replace Constructors with Creation Methods Example

Continuando la serie di post sui smells, inizio ad introdurre i possibili smell e le relative possibili soluzioni.
Il primo che affronteremo riguarda una classe con 5 costruttori (anche se personalmente già 2 costruttori sono troppi):
public class Loan
{
public Loan(string commitment, int riskRating, int maturity)
public Loan(string commitment, int riskRating, int maturity, DateTime expiry)
public Loan(string commitment, string outstanding, int riskRating, int maturity, DateTime expiry)
public Loan(int capitalStrategy, string commitment, int riskRating, int maturity, DateTime expiry)
public Loan(int capitalStrategy, string commitment, string outstanding, int riskRating, int maturity, DateTime expiry)
}

Ecco come si presenterà la classe una volta rifattorizzata:

public class Loan
{
private Loan(int capitalStrategy, string commitment, string outstanding, int riskRating, int maturity, DateTime expiry)
public static Loan createTermLoad(string commitment, int riskRating, int maturity)
{
return new Loan(-1, commitment, "", riskRating, maturity, DateTime.MinValue);
}

public static Loan createTermLoad(int capitalStrategy, string commitment,
string outstanding, int riskRating, int maturity)
{
return new Loan(capitalStrategy, commitment, outstanding, riskRating, maturity,
DateTime.MinValue);
}

public static Loan createRevolver(string commitment, string outstanding,
int riskRating, DateTime expiry)
{
return new Loan(-1, commitment, outstanding, riskRating, -1, DateTime.MinValue);
}

public static Loan createRevolver(int capitalStrategy, string commitment,
string outstanding, int riskRating, int maturity)
{
return new Loan(capitalStrategy, commitment, outstanding, riskRating,
maturity, DateTime.MinValue);
}

public static Loan createRCTL(string commitment, string outstanding,
int riskRating, int maturity, DateTime expiry)
{
return new Loan(-1, commitment, outstanding, riskRating, maturity, expiry);
}

public static Loan createRCTL(int capitalStrategy, string commitment,
string outstanding, int riskRating, int maturity,
DateTime expiry)
{
return new Loan(capitalStrategy, commitment, outstanding, riskRating, maturity, expiry);
}
}

Motivazione:
Perchè dovrei togliere i miei molteplici costruttori a favore di una seria di metodi statici?
I costruttori non comunicano qual'è la loro intenzione nel momento in cui istanziano la classe, così più costruttori abbiamo all'interno della nostra classe più è probabile che dovremo andare a controllare ogni singolo costruttore per capire cosa fa (cosa impensabile se neanche abbiamo i sorgenti).

Se servirà creare un costruttore con la stessa firma, ma che istanzia l'oggetto in maniera diversa, non si potrà inserire.
Se il software avrà una certa dimensione e tanti costruttori è probabile che molti di questi non verranno utilizzati e vi rimaranno lì perchè anche capire quali vengono usati e quali no è un lavoro molto complicato.
 




Benefici e non
+ Comunica quale tipo di istanza stiamo creando
+ Evita i limiti dei costruttori
+ E' più semplice trovare i metodi non usati
- E' un metodo non standard per istanziare gli oggetti. Così potreste trovarvi alcune classi con i costruttori classici e altre no.
 
Per questi post sto prendendo, molto, spunto da libro Refactoring To Patterns di Joshua Kerievsky.

No comments:

Post a Comment