Per interfaccia fluente si intende la possibilità di invocare una serie di funzioni a cascata. Questa tecnica è utile per evitare di avere una funzione con molti parametri, o per rendere più elegante e leggibile il codice.
Ecco uno spezzone di codice C#, relativo a una classe che espone, per la propria costruzione, un'interfaccia fluente:
public MqttClient(string name, EuEvent.Queue eventQueue) : base(name)
{
// Init
_clientId = name;
_eventQueue = eventQueue;
_messageQueue = new EuQueue<Message>("self");
// ... altro codice ...
}
public MqttClient WithBrokerHost(string brokerHost)
{
_brokerHost = brokerHost;
return this;
}
public MqttClient WithCredentials(Tuple<string, string> credentials)
{
_credentials = credentials;
return this;
}
Ed ecco come il chiamante può utilizzare l'interfaccia fluente per costruire l'oggetto con specifiche caratteristiche:
var mqttClient = new MqttClient("myclient", EventQueue)
.WithBrokerHost("myhost")
.WithCredentials(new Tuple<string, string>("foo", "boo"));
Come si può apprezzare, il codice è molto espressivo e auto-esplicativo. L'unico accorgimento, nel predisporre l'interfaccia fuente, è che le funzioni coinvolte restituiscano l'oggetto stesso come valore di ritorno.
In Dart si può utilizzare lo stesso metodo visto sopra per C#. Ma è possibile anche semplificare la sintassi, e nel contempo rendere il meccanismo più potente:
MqttClient(String name, this._eventQueue) :
_clientId = name,
_messageQueue = MessageQueue<Message>('self') {});
void withBrokerHost(String brokerHost) {
_brokerHost = brokerHost;
}
void withCredentials(Tuple<String, String> credentials) {
_credentials = credentials;
}
Si noti che le funzioni dell'interfaccia fluente hanno tipo di ritorno void. In questo caso il chiamante utilizzerà l'operatore .. (doppio punto):
var mqttClient = MqttClient("myclient", EventQueue)
..withBrokerHost("localhost")
..withCredentials(Tuple<string, string>("foo", "boo"));
L'operatore .. permette di mettere in cascata le chiamate, restituendo automaticamente l'istanza dell'oggetto per la chiamata successiva.
In che senso il meccanismo è più potente? Supponiamo di derivare una classe da MqttClient, diciamo MyMqttClient. Essa erediterà le funzioni fluenti, ma nell'invocarle con .. il tipo di oggetto restituito per la chiamata a cascata sarà MyMqttClient, non MqttClient.
Per ottenere la stessa semantica in C#, occorrerebbe utilizzare la type injection, aggiungendo alla classe base un parametro di tipo che permette, in fase di utilizzo, di specificare il tipo effettivo da restituire nelle funzioni dell'interfaccia fluente.
Giorgio Barchiesi
Albo degli Ingegneri Sez. A, N. 4027 della Prov. di Trento
P.IVA 02370260222, C.F. BRC GRG 58L26 C794R
Copyright © 2015-2024 Giorgio Barchiesi - Tutti i diritti riservati