Uso dei mixin in Ruby
Pagina 1 di 2
A volte capita di voler creare una classe di oggetti che abbiano "questa" funzionalità, ma anche "questa" e "quest'altra", che sono magari già state scritte altrove nel nostro codice sorgente.
In altre parole, vorremmo creare una classe che prenda in prestito metodi e proprietà definiti in altre parti del codice sorgente o in qualche libreria.
Viceversa, vorremmo raccogliere funzionalità uguali sparse per il nostro codice sorgente in un unico punto accessibile a tutti. Come fare?
I puristi della programmazione orientata agli oggetti inorridiscono e sostengono - a parer mio non del tutto a torto - che ogni necessità di questo tipo può essere risolta con un uso appropriato del polimorfismo.
Altri, specie se provengono da esperienze con linguaggi tipo il C++, sostengono che proprio per queste esigenze si usa l'ereditarietà multipla.
Linguaggi pragmatici come Ruby, invece, affrontano la questione mettendo a disposizione una tecnica che si chiama "mixin", dal nome - sembra! - che un gelataio del Massuchussets dava al suo gelato composto da vari gusti (crema, cioccolato...)
I mixin in Ruby
Tecnicamente, in Ruby i mixin si implementano utilizzando all'interno di classi, codice definito in altrettanti moduli (module).
Per fare un esempio banale, supponiamo che io voglia implementare un word processor che automaticamente mi stampi le cordialità di una lettera commerciale. Da utente voglio inserire solo i dati necessari, cioè il destinatario e il messaggio. Il programma penserà alle varie cordialità tipo: "Egregio signore" e "Cordiali Saluti".
Cominciamo col definire le cordialità in un apposito modulo:
module CordialitaLettera
def inizio(destinatario)
return "Egregio sig."+destinatario+",\n"
end
def firma(lettera)
return lettera+"\n"+"Cordiali saluti,\nCarlo Rossi"
end
end
Niente di particolare, dunque, solamente due metodi in grado di modificare il testo ricevuto in input.
Scriviamo ora una classe "mixata" a questi metodi, un mixin appunto:
class Lettere
include CordialitaLettera
def stampaLettera(destinatario, messaggio)
lettera = inizio(destinatario)
lettera += messaggio
puts firma(lettera)
end
end
La classe Lettere di cui sopra ha un metodo che, prendendo in input le sole parti variabili della lettera, la formatta con le cordialità definite nel modulo.
Come potete vedere la sintassi è del tutto analoga a quella dell'ereditarietà in Ruby, però, a differenza di quest'ultima, possiamo implementare in una classe un numero a piacere di moduli - mentre come è noto, una classe può essere derivata da una e una sola classe padre (Ruby non supporta l'ereditarietà multipla!)
Ad esempio possiamo scrivere:
def main()
lEngine = Lettere.new
lEngine.stampaLettera('Alessio Saltarin',
'Ho appena provveduto al bonifico
da Lei richiesto.')
puts
lEngine.stampaLettera('Matteo Pisconi',
'Mi mandi il fax al nr.038283873.')
end
che restituisce:
Egregio sig.Alessio Saltarin, Ho appena provveduto al bonifico da Lei richiesto. Cordiali saluti, Carlo Rossi
Egregio sig.Matteo Pisconi, Mi mandi il fax al nr.038283873. Cordiali saluti, Carlo RossiQuesta tecnica, tra l'altro, ci permette di assimilare l'uso dei mixin a quello delle interfacce in Java: infatti, se una classe si "mixa" con un modulo, di fatto ne implementerà i metodi (dunque rispetta una certa interfaccia).







