]]>
Questo è un post autocelebrativo sull’arte della tagliatella fatta a mano. Arte che sto con fatica, ma anche con divertimento imparando a mettere in pratica come testimoniano le foto seguenti.
]]>
L’esperienza non è stata affatto negativa, anche se dal punto di vista di un programmatore C#, Java sembra un po’ più spartano e “C like” (insomma un po’ di vecchiaia e polvere la noto).
Tuttavia in questo post mi voglio soffermare su un solo aspetto che ho trovato particolarmente “sconveniente” in Java e che invece trovo particolarmente comodo in C#: la gestione e dichiarazione di eventi “custom”.
Come primo step, in C# ho a disposizione il supporto nativo per i delegati che altro non sono che la rappresentazione tipizzata di un sano e vecchio puntatore a funzione. Quindi per definire un evento, inizio col dichiarare il delegato che ne rappresenta il suo handler:
public delegate bool MyEventHandler(int myEventData);
In Java non ho scelta, devo definire un’interfaccia ed usare una classe anonima per implementarla. Il delegato precedente si traduce quindi in questa interfaccia:
public interface MyEventListener { boolean onMyEvent(int myEventData); }
E fin qui direi che i due approcci siano piuttosto simili, anzi propendo un po’ di piu’ per l’approccio Java che trovo sicuramente elegante.
Il problema però è che per implementare un evento, oltre alla firma del metodo handler, devo gestire una lista degli oggetti che si sono sottoscritti ai quali inviare poi la notifica. In C# questo step si riduce a dichiarare l’evento ed automaticamente il compilatore si occupa di generare tutto il codice necessario “trasformando” il mio delegato in un delegato multicast, mantenendo così di fatto la lista dei vari sottoscrittori etc…
In pratica questo è il codice sufficiente, tutto il resto è automatico:
public event MyEventHandler MyEvent;
Semplicemente dichiarando l’evento posso sottoscrivermi, con gli operatori += e -= (pessima scelta da parte di Microsoft):
this.MyEvent += new MyEventHandler(this.OnMyEvent); this.MyEvent -= new MyEventHandler(this.OnMyEvent);
e notificare l’evento invocandolo:
if (MyEvent != null) MyEvent(10);
In Java non ho a disposizione nessuna facilitazione ed in pratica devo reimplementare per ogni evento custom le 3 funzioni necessarie al mantenimento della lista, usualmente nella forma:
addMyEventListener(MyEventListener listener); removeMyEventListener(MyEventListener listener); dispatchMyEvent();
E mantenere la lista dei sottoscrittori in un ArrayList o in altra collection (ad es. una EventListenerList che comunque trovo bruttina) in una variabile a livello di classe.
Dal punto di vista dell’utilizzo in Java posso sottoscrivermi utilizzando una classe anonima (notare il new dell’interfaccia MyEventListener)
addMyEventListener(new MyEventListener() { @Override public boolean onMyEvent(int myEventData) { // event handler } });
e per notificare l’evento è sufficiente chiamare la
dispatchMyEvent();
Non male, ma scrivere il trittico di funzioni add / remove / dispatch per ogni evento è tedioso e soggetto ad errori.
La domanda sorge spontanea: si può fare di meglio?
Premesso che “meglio” per me significa:
Che fare?
Lo spunto l’ho preso da C# 2.0 che con l’introduzione dei generics e di alcune altre classi di utilità ha snellito l’implementazione degli eventi, standardizzando i parametri del delegato “handler” senza sacrificarne però le potenzialità.
In pratica oggi li dichiaro quasi sempre “genericamente” in questo modo:
public class MyEventArgs : EventArgs { public int MyEventData = 0; // sarebbe meglio usare una proprietà } public class MyEventProducer { public event EventHandler<MyEventArgs> MyEvent; public void MyMethod () { if (MyEvent != null) MyEvent(this, new MyEventArgs()); } } public class MyEventConsumer { private MyEventProducer producer; public MyEventConsumer () { producer = new MyEventProducer (); producer.MyEvent += new EventHandler<MyEventArgs>(this.OnMyEvent); } private void OnMyEvent(object sender, MyEventArgs e) { // event handler } }
Dato che anche Java ha i generics, deve essere possibile realizzare qualche cosa di simile ed in effetti, anche se le mie conoscenze in materia sono vecchie solo di qualche giorno, implementando una semplice classe di utilità sono riuscito nell’intento.
public class EventArgs { public static final EventArgs Empty = new EventArgs(); } public interface EventListener<T extends EventArgs> { void onEventReceived(Object sender, T args); } public class Event<A extends EventArgs> { private List<EventListener<A>> listeners = new LinkedList<EventListener<A>>(); public void addListener(EventListener<A> listener) { listeners.add(listener); } public void removeListener(EventListener<A> listener) { while(listeners.remove(listener)) ; } public void dispatch(Object sender, A args) { for(EventListener<A> listener : listeners) { listener.onEventReceived(sender, args); } } } public class EventProducer { public final Event<EventArgs> simpleEvent = new Event<>(); public void run() { System.out.println("dispatching SimpleEvent..."); simpleEvent.dispatch(this, EventArgs.Empty); } } public class EventConsumer { private EventProducer producer; public EventConsumer() { producer = new EventProducer(); producer.simpleEvent.addListener(new EventListener<EventArgs>() { @Override public void onEventReceived(Object sender, EventArgs args) { System.out.println("SimpleEvent received"); } }); } public void run() { producer.run(); } public static void main (String[] args) { EventConsumer consumer = new EventConsumer(); consumer.run (); } }
In pratica il grazie alla classe generica Event ho mantenuto la forte tipizzazione dei vari metodi di gestione dell’evento sacrificando pochi aspetti quali:
Probabilmente alla lunga il punto 2 può causare qualche problema, ma per ora non vedo particolari controindicazioni, dato che l’uso di classi anonime mi sembra sia una pratica piuttosto diffusa in Java.
Qui il progetto eclipse completo con i miei esperimenti: CSharpLikeEvents.zip
E’ probabile che la soluzione proposta sia banale, già acquisita o completamente errata, ma cercando anche se non approfonditamente in rete non ho trovato nulla in proposito.
]]>Il risultato sono una serie di brani, che tenterò di registrare di volta in volta durante la pausa pranzo nella mia vecchia camera prima che il trasloco sia definitivamente completato.
E’ cosi che aggiungo “Danza Liquida” ad Improvvisando.
]]>Ora sento la mancanza di: un tavolo, delle sedie, il cestino dell’immondizia, il bicchiere per lo spazzolino, il buzzicone dei panni sporchi, una scrivania, piatti, posate, una mensola in pietra per completare la cucina, una libreria, uno sgabuzzino, scrivanie, un divano, un tappeto, un mobile per le scarpe, l’appendiabiti…
]]>La giornata é iniziata presto, sono uscito di casa alle 6.30 di mattina con l’obbiettivo di raggiungere “il pizzo”, montagna che sovrasta la piccola comunità agricola di Vetice sui Sibillini.
Alle 9 sono già in marcia, imbocco il sentiero, ma dopo poco più di un chilometro, un cancello di filo spinato mi sbarra il passo. Come al solito penso di aver sbagliato strada, del resto la fonte che ho preso come riferimento é circondata da diversi percorsi, quindi torno indietro e ne prendo un altro che mi porta di nuovo ad un recinto di filo spinato, poi un altro che scopro svoltare nella direzione sbagliata, scoraggiato non mi rimane che tornare al punto di partenza vicino alla macchina e ricominciare.
Due chiacchiere con un allevatore del posto e mi convinco che il secondo sentiero intrapreso sia quello giusto. Di nuovo in marcia, un’altra ora sotto il sole e mi ritrovo ai piedi di una frana: la strada sbarrata, al massimo potrei avanzare mani e piedi, “non può essere” penso e giro i tacchi verso valle. Mentre ridiscendo mi torna in mente la risposta dell’allevatore “sbarrato col filo spinato? probabilmente é solo un recinto per i cavalli, lo apri e prosegui…”, sì certo un recinto per i cavalli… ci sono! La mappa é chiara, bisogna andare diritti e abbassarsi un po’ di quota e l’unico sentiero dritto in leggera discesa é il primo!
Che ironia proprio il primo, quello che avevo preso alle 9 ed ormai sono quasi 4 ore che giro a vuoto. Rifaccio la strada apro il cancello proseguo e con mia sorpresa constato che questo é quello giusto.
L’inizio é semplice poi piano piano la salita si fa ripida, la stanchezza aumenta passo dopo passo, mi gira la testa, il sentiero intanto é diventato stretto e panoramico, a sinistra un bel salto di diverse decine di metri, sono quasi in cima, poco prima dell’impettata finale, lo strappo, la resa, vomito. Mi riposo per un po’, provo a fare qualche altro metro, ma non mi rimane che constatare la mia sconfitta e tornare sui miei passi.
Arrivo a valle, poco meno di 7 ore di cammino, guardo “il pizzo”: la mia prima sconfitta, la mia prima resa.
Nonstante dal mio racconto sembro essere solo, in realtà ero accompagnato da Sergio, che intanto sta provvedendo al mio sputtanamento con dovizia di particolari su scala locale.
Tuttavia sarà il trasferimento imminente o i continui bagordi, ma mi è rimasta una strana sensazione con la quale convivo in questo mio secondo giorno da 38enne. Così per scaramanzia e anche perché l’avevo detto uscendo dall’ufficio aggiungo un nuovo semplice (i soliti 4 accordi) brano ad improvvisando
In tema di pacchetti, traslochi e di occasioni mancate: La scatola
]]>
Questo é l’attrezzo: classico tappo del corpo macchina forato più o meno al centro con applicato un foglio di stagnola a sua volta forato con uno spillo.
Ed ecco la mia prima foto stenopeica digitale (contro luce con una posa di 1 secondo circa e sovraesponendo di 1 stop):
Non so di preciso come sia riuscito ad ottenere questo effetto arcobaleno, comunque mi piace.
Tuttavia il foro ha evidenziato tutta la polvere depositata sul sensore, moltissima ahimé, ma del resto c’era da aspettarselo dato che negli ultimi 6 anni questa povera 350D mi ha seguito in lungo e in largo per deserti, cascate e montagne sparse per quattro dei nostri sei continenti.
]]>