Non commentare il codice, rendilo più leggibile con le Fluent Interface
Il method chaining, ovvero la possibilità di concatenare le chiamate ai metodi di una interfaccia, si ottiene definendo come valore di ritorno l’istanza corrente della classe a cui appartiene il metodo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
namespace FluentInterface.Model.NoFluent { using System; using System.Text; public class Train { public string Number { get; set; } public string DepartureStation { get; set; } public string Destination { get; set; } public DateTime DepartureDate { get; set; } public int Class { get; set; } public Train(){ } public Train(string number, string departureStation, string destination, DateTime departureDate, int _class) { this.Number = number; this.DepartureStation = departureStation; this.Destination = destination; this.DepartureDate = departureDate; this.Class = _class; } } } |
Nel codice cliente andiamo poi a prenotare il biglietto per un particolare treno:
1 2 3 4 5 6 |
bookingService.PlaceBookingFor( new Train("9513", "Milano C.le", "Roma Termini", DateTime.Parse("2010/02/12 8:20"), 1) ); |
Come possiamo notare il codice non è per niente leggibile, dobbiamo infatti ricorrere alla definizione del costruttore della classe per capire il significato dei parametri passati.
1 2 3 4 5 6 7 8 9 10 |
bookingService.PlaceBookingFor( new Train() { Number = "9513", DepartureStation = "Milano C.le", Destination = "Roma Termini", DepartureDate = DateTime.Parse("2010/02/12 8:20"), ClassNumber = 1 } ); |
Vediamo quindi come una interfaccia “fluente” può rendere questo codice più leggibile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
namespace FluentInterface.Model.Fluent { using System; using System.Text; public enum Class { First = 1, Second = 2, Third = 3 } public class Train { public string Number { get; set; } public string DepartureStation { get; set; } public string Destination { get; set; } public DateTime DepartureDate { get; set; } public int ClassNumber { get; set; } public Train(){ } public Train(string number, string departureStation, string destination, DateTime departureDate, int classNumber) { this.Number = number; this.DepartureStation = departureStation; this.Destination = destination; this.DepartureDate = departureDate; this.ClassNumber = classNumber; } #region Fluent Interface public Train Nr(string number) { this.Number = number; return this; } public Train From(string departureStation) { this.DepartureStation = departureStation; return this; } public Train To(string destination) { this.Destination = destination; return this; } public Train DepartureAt(DateTime departureDate) { this.DepartureDate = departureDate; return this; } public Train DepartureAt(string departureDate) { this.DepartureDate = DateTime.Parse(departureDate); return this; } public Train In(Class _class) { this.ClassNumber = (int)_class; return this; } #endregion } } |
Vediamo come cambia il nostro codice cliente per quanto riguarda la prenotazione di un biglietto ferroviario:
1 2 3 4 5 |
bookingService.PlaceBookingFor(new Train().Nr("9513") .From("Milano C.le") .To("Roma Termini") .DepartureAt("12/2/09 8:20") .In(Class.First)); |
Possiamo migliorare ancora trasformando il metodo Nr in una “static factory”, ovvero implementando al suo interno la creazione di una istanza della classe Train, così:
1 2 3 4 5 6 |
public static Train Nr(string number) { Train train = new Train(); train.Number = number; return train; } |
La differenza rispetto al codice di prima è minima, ma evidente:
1 2 3 4 5 |
bookingService.PlaceBookingFor(Train.Nr("9513") .From("Milano C.le") .To("Roma Termini") .DepartureAt("12/02/2009 8:20") .In(Class.First)); |
In conclusione ci sono molti modi per aiutare noi stessi e altri programmatori a capire che cosa fa il nostro codice, il più importante di tutti rimane sempre il commento, ma le fluent interface sono un valido alleato per combattere le lunghe sedute davanti al reflector!
MEF in Action: slide e codice dell’evento
Grande partecipazione ieri sera all’hands on lab organizzato da 1nn0va presso il Consorzio Universitario di Pordenone. Di seguito potete trovare le slide e il codice della mia sessione sul Managed Extensibility Framework.
Codice di esempio pronto per il download >> |
Download |
AntiPatterns, i vizi del programmatore: slide e codice
Ho pubblicato su slideshare le slide dell’evento 1nn0va di venerdì sera. Per chi fosse interessato sono disponibili per il download i progetti di esempio, trovate il link qui sotto dopo la presentazione.
Codice di esempio pronto per il download >> |
Download |