Visualizzazione dei risultati da 1 a 6 su 6
  1. #1

    Esempi chiari e completi sul funzionamento degli eventi in Java

    Salve a tutti,

    c'è qualche anima pia capace di fare un paio di esempi e farmi capire il meccanismo che è alla base degli eventi in Java puro (senza interfacce grafiche ecc.)?
    Da quello che ho capito al momento, in Java la questione degli eventi sfrutta un pattern chiamato Observer ed è richiesto l'uso di interfacce che prendono il nome di Listener.
    Se io volessi creare una classe Cane in grado di sollevare un evento quando l'animale ha fame e, in questo caso, richiedere l'intervento di un oggetto di tipo Padrone che riempie la sua ciotola come dovrei fare?
    Qualcuno saprebbe realizzare in modo didattico qualcosa del genere (o anche d'altro tipo se serve allo scopo).
    In rete c'è di tutto e di più ma nulla di semplice e chiaro che spieghi passo passo la faccenda senza ricorrere alle Gui oppure ad Android e cose così.
    Baci.
    Filo

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Quote Originariamente inviata da filograndipad2 Visualizza il messaggio
    c'è qualche anima pia capace di fare un paio di esempi e farmi capire il meccanismo che è alla base degli eventi in Java puro (senza interfacce grafiche ecc.)?
    Da quello che ho capito al momento, in Java la questione degli eventi sfrutta un pattern chiamato Observer ed è richiesto l'uso di interfacce che prendono il nome di Listener.
    Se io volessi creare una classe Cane in grado di sollevare un evento quando l'animale ha fame e, in questo caso, richiedere l'intervento di un oggetto di tipo Padrone che riempie la sua ciotola come dovrei fare?
    Allora, vediamo innanzitutto la cosa a livello concettuale (poi se vuoi del codice di esempio, si può fare).

    Ti è chiaro innanzitutto come si può realizzare il meccanismo di "callback" (richiamata, volendolo tradurre in italiano) tramite una interfaccia Java? C'è una interfaccia X che dichiara un metodo astratto (o più di uno). Una classe C riceve 1 oggetto che implementa X, lo può ricevere tramite costruttore o con un metodo apposito, non ha molta importanza ora. Notare che alla classe C non interessa di che classe è quell'oggetto ricevuto, a C basta "vederlo" di tipo X, la interfaccia. Quando un oggetto di classe C vuole "notificare" qualcosa, invoca quel metodo di X sull'oggetto che si è tenuto da qualche parte come variabile di istanza.

    Attenzione che questo NON è un Observer, né un listener (listener intendendo anche proprio quelli specifici di AWT/Swing). È semplicemente l'uso basilare, minimale della programmazione ad oggetti per realizzare un meccanismo di "callback". Le interfacce si usano solitamente proprio per rappresentare un "contratto" tra due parti.

    Il Observer è un design pattern specifico, che può fare certamente uso delle interfacce. Infatti l'entità "observer" (chi osserva e riceve le notifiche) è generalmente descritto a livello astratto da una interfaccia. Il "soggetto" (Subject o anche Observable) che è l'entità da cui si originano le notifiche tipicamente dovrebbe essere anch'esso descritto da una interfaccia, sebbene in casi specifici possa essere una classe concreta.

    Una implementazione del pattern Observer è già presente nel framework standard, dove java.util.Observer è una interfaccia mentre java.util.Observable è una classe concreta. Il fatto che sia una classe può ovviamente essere un limite a seconda di dove lo si vorrebbe usare.
    Questa nel framework comunque è solo una possibile implementazione, chiunque ne può realizzare un'altra più in linea con il design pattern Observer "teorico".

    Un Observer però è qualcosa di più del meccanismo di callback detto prima: innanzittutto la questione concettuale è che l'Observer si usa tipicamente quando si vuole notificare un cambiamento di stato di un oggetto (es. una proprietà dell'oggetto che cambia valore).
    Inoltre nel pattern Observer il soggetto tipicamente mantiene un elenco di N osservatori, quindi non solo uno. E tipicamente viene permessa l'aggiunta così come anche la rimozione di un osservatore.

    Quando si parla di listener bisogna precisare se si intende il termine in senso generale (un "ascoltatore", come potrebbe essere la callback detta all'inizio) oppure se si intende in modo specifico i listener come quelli delle interfacce grafiche AWT/Swing. I listener di AWT/Swing sono una "specializzazione" del pattern Observer e in AWT/Swing sono implementati usando una serie di linee guida e convenzioni ben precise.
    Tra l'altro i listener di AWT/Swing servono più in generale per notificare "eventi", quindi non necessariamente un cambio di stato di un oggetto.

    Fin qui è tutto chiaro?
    Ultima modifica di andbin; 23-06-2018 a 21:17
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  3. #3
    Grazie mille per le informazioni teoriche. La questione mi è più o meno chiara ma quello che non riesco al momento a fare e realizzare in pratica delle classi in Java che interagiscono per eventi. Potresti scrivere delle semplici e chiare linee di codice di esempio dove è possibile cogliere tutta la questione? Nel post precedente facevo l'esempio della classse Cane e di quella Padrone giusto per scrivere qualcosa di concreto. Grazie ancora per l'aiuto.

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Quote Originariamente inviata da filograndipad2 Visualizza il messaggio
    Potresti scrivere delle semplici e chiare linee di codice di esempio dove è possibile cogliere tutta la questione? Nel post precedente facevo l'esempio della classse Cane e di quella Padrone giusto per scrivere qualcosa di concreto.
    Nel tuo esempio iniziale, Padrone e Cane, dicevi "quando l'animale ha fame". Ma l'animale sarà un oggetto, no? E non ha vita autonoma, nel senso che come oggetto sarà "usato" e pilotato (con metodi) da altre entità. Quindi quando è che DA SOLO (senza che il Padrone faccia qualcosa) l'animale arriva ad uno stato da avere fame? Ci sarebbero da considerare diverse cose ....

    Ti faccio invece un altro esempio, facilmente comprensibile: l'automobile e il cruscotto. Si vuole che il cruscotto mostri delle informazioni (io farò dei banali System.out.println) quando "qualcosa" cambia nello stato della automobile.

    Innanzitutto definisco la interface Java che rappresenta il "contratto" tra l'automobile e chi vuole ricevere le notifiche:

    codice:
    public interface AscoltatoreAutomobile {
        void macchinaAccesa();
        void macchinaSpenta();
        void marciaCambiata(int marcia);
        void marciaInFolle();
    }

    Poi scrivo l'Automobile, che "sa" di 1 solo possibile oggetto "ascoltatore" (AscoltatoreAutomobile):

    codice:
    public class Automobile {
        private boolean accesa;
        private int marcia;
        private AscoltatoreAutomobile ascoltatore;
    
        public Automobile() {
            accesa = false;    // inizialmente spenta
            marcia = 0;        // "folle"
        }
    
        public void setAscoltatore(AscoltatoreAutomobile ascoltatore) {
            this.ascoltatore = ascoltatore;
        }
    
        public void accendi() {
            if (!accesa) {
                accesa = true;
                if (ascoltatore != null) {
                    ascoltatore.macchinaAccesa();
                }
            }
        }
    
        public void spegni() {
            if (accesa) {
                accesa = false;
                if (ascoltatore != null) {
                    ascoltatore.macchinaSpenta();
                }
            }
        }
    
        public void aumentaMarcia() {
            if (marcia < 5) {
                marcia++;
                if (ascoltatore != null) {
                    ascoltatore.marciaCambiata(marcia);
                }
            }
        }
    
        public void scalaMarcia() {
            if (marcia > 1) {
                marcia--;
                if (ascoltatore != null) {
                    ascoltatore.marciaCambiata(marcia);
                }
            }
        }
    
        public void impostaMarciaFolle() {
            if (marcia != 0) {
                marcia = 0;
                if (ascoltatore != null) {
                    ascoltatore.marciaInFolle();
                }
            }
        }
    }

    Quindi il Cruscotto che come si vede qui sotto, è una semplice e banale implementazione di AscoltatoreAutomobile:

    codice:
    public class Cruscotto implements AscoltatoreAutomobile {
        @Override
        public void macchinaAccesa() {
            System.out.println("ACCESA");
        }
    
        @Override
        public void macchinaSpenta() {
            System.out.println("SPENTA");
        }
    
        @Override
        public void marciaCambiata(int marcia) {
            System.out.println("MARCIA " + marcia);
        }
    
        @Override
        public void marciaInFolle() {
            System.out.println("MARCIA IN 'FOLLE'");
        }
    }

    Poi un piccolo main di prova:

    codice:
    public class ProvaAutomobile {
        public static void main(String[] args) {
            Automobile automobile = new Automobile();
            Cruscotto cruscotto = new Cruscotto();
    
            automobile.setAscoltatore(cruscotto);
    
            automobile.accendi();
            automobile.accendi();      // non fa nulla e non notifica nulla
            automobile.aumentaMarcia();
            automobile.aumentaMarcia();
            automobile.scalaMarcia();
            automobile.spegni();
            automobile.impostaMarciaFolle();
        }
    }

    Come si vede nel main, viene invocato setAscoltatore passando direttamente l'oggetto Cruscotto. Cruscotto implementa AscoltatoreAutomobile quindi per il compilatore è perfettamente lecito.

    Il punto importante è che Automobile non "sa" nulla di Cruscotto e viceversa Cruscotto non "sa" nulla di Automobile! Grazie alla interfaccia che fa da "contratto" per la notifica, le due entità sono completamente disaccoppiate.

    Tutto questo, come ho detto prima, NON è un Observer in senso stretto, né un listener inteso come quelli di AWT/Swing. È semplicemente l'uso basilare della programmazione ad oggetti, in questo caso l'uso di una interfaccia, per applicare un meccanismo di notifica (o "callback").


    P.S. il codice è perfettamente compilabile e provabile. Verificalo pure.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  5. #5
    Ti ringrazio ancora una volta per la cortese disponibilità. Hai fatto chiarezza in molti miei dubbi ma mi sa che ho ancora un po' da studiare e da capire per cogliere appieno la questione della gestione degli eventi in particolar modo con riguardo ad Android. L'interesse per Java deriva dal fatto che vorrei sviluppare app nativamente con Android Studio senza più fare uso di framework cross-platform. Ad esempio quello che ancora mi è poco chiaro è il significato del seguente codice relativo al click su un pulsante:

    mTrueButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v){
    checkAnswer(true);
    updateQuestion();

    }
    });setOnClickListener è il metodo per registrarsi sul listener?
    il parametro View.OnClickListener dovrebbe essere un'interfaccia definita nella classe View che contempla il metodo onClick ma quand'è che passo un oggetto View come parametro di questo metodo onClick? Nello snippet sopra non si fa nessun riferimento all'oggetto di nome 'v' di tipo View come da parametro di onClick()

    Comunque... mi sta scoppiando la testa.
    Grazie per l'attenzione

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Quote Originariamente inviata da filograndipad2 Visualizza il messaggio
    setOnClickListener è il metodo per registrarsi sul listener?
    Sì, esatto.

    Quote Originariamente inviata da filograndipad2 Visualizza il messaggio
    il parametro View.OnClickListener dovrebbe essere un'interfaccia definita nella classe View
    Non ho sottomano la documentazione di Android ma OnClickListener è sicuramente una interface. E nel caso specifico è una "nested" (innestata) interface della classe View.

    Quote Originariamente inviata da filograndipad2 Visualizza il messaggio
    ma quand'è che passo un oggetto View come parametro di questo metodo onClick?
    Quando vedi una forma del tipo

    new Tipo( ... ) { ..... }

    Questa è una "anonymous inner class", ovvero una classe anonima. E' anonima perché il nome non lo sai (non è nel sorgente che scrivi, lo sceglie il compilatore).
    Sostanzialmente è la definizione di una classe (vedi che c'è il blocco { } con metodi dentro) ma che è istanziata nello stesso punto in cui è definita.
    Una classe anonima può fare solo UNA di queste due cose: estendere una classe OPPURE implementare una interfaccia.
    Quindi in quel caso viene definita una classe anonima che implementa OnClickListener (e implicitamente estende Object).
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  7. #7
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,303
    ma quand'è che passo un oggetto View come parametro di questo metodo onClick?
    Non sei tu a passare l'oggetto View a quel metodo: sarà il sistema a passare l'oggetto quando verrà sollevato l'evento.
    Quando l'utente fa clic sul pulsante, il sistema chiamerà il metodo onClick() passandogli il riferimento al pulsante che è stato premuto. In questo modo la tua applicazione verrà "notificata" del clic e potrà agire di conseguenza.


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

Tag per questa discussione

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.