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

    Observer - Quale variabile è cambiata

    Un saluto a tutti.
    Studio Java da poco e sto affrontando l'argomento Pattern sia MVC che Observer.
    Vorrei proporre un quesito più che un problema.
    Il model (Observable) informa la View (Observer) che c'è stato un cambiamento.
    La view, nel suo metodo update, può sapere quale variabile del model è cambiata ed
    aggiornare solo la label interessata? Magari senza usare IF o SWITCH ma usando il
    polimorfismo?
    Mi spiego meglio.
    Nel mio lavoro ho a che fare con dei Sili che contengono dei materiali ed allora ho
    buttato giù questo model:
    codice:
    package observerexample4;
    import java.util.Observable;
    
    public class SiloModel extends Observable {
        private Integer numero;    
        private String  materiale;
        private Integer peso;
        
        public SiloModel(Integer numero, String materiale, Integer peso){
            setNumero(numero);
            setMateriale(materiale);
            setPeso(peso);
        }
        public void setNumero(Integer numero){
            this.numero=numero;
            setChanged();
            notifyObservers();
        }
        public void setMateriale(String materiale){
            this.materiale=materiale;
            setChanged();
            notifyObservers();
        }
        public void setPeso(Integer peso){
            this.peso=peso;
            setChanged();
            notifyObservers();
        }
        public Integer getNumero(){return this.numero;}
        public String getMateriale(){return this.materiale;}
        public Integer getPeso(){return this.peso;}
    }
    Faccio notare che il numero del silo è un dato che non cambia quasi mai, viene impostato
    all'inizio e rimane sempre quello. Il materiale può cambiare quando il silo si svuota e può
    essere riempito con un altro tipo di materiale. Il peso invece è un dato che cambia molto
    frequentemente quando il silo è in fase di carico/scarico.
    Quindi le variabili del model possono essere molte e con frequenza di aggiornamento diverse.
    Passiamo alla View:
    codice:
    package observerexample4;
    
    import java.awt.Frame;
    import java.awt.Label;
    import java.awt.Panel;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.util.Observable;
    import java.util.Observer;
    
    public class SiloView implements Observer {
        private Frame frame=new Frame();
        private Label materiale=new Label();
        private Label peso=new Label();
        private SiloModel model;
        
        public SiloView(SiloModel m){
            model=m;
            model.addObserver(this); // mi registro come osservatore
            
            Panel p1 = new  Panel();
            p1.add(materiale);
            p1.add(peso);
            
           // preparazione della view
            materiale.setText(model.getMateriale());
            peso.setText("" + model.getPeso());
            peso.setAlignment(Label.CENTER);
            
            frame.setTitle("Silo " + model.getNumero());
            frame.setSize(300,60);
            frame.setLocation(100,100);
            frame.add(p1);
    
            frame.addWindowListener(new WindowAdapter(){
                @Override
                public void windowClosing (WindowEvent ev){
                    frame.setVisible(false);
                }
            });
            this.frame.setVisible(true);
        }
        public void update(Observable o, Object arg) {
            peso.setText(""+model.getPeso());
            materiale.setText(model.getMateriale());
        }
    }
    Nel metodo update aggiorno tutte le label con i dati del model e nella maggior
    parte dei casi non è necessario aggiornare tutto.
    E qui riformulo la domanda:
    Nel metodo update, posso sapere se è cambiato solo il materiale (aggiorno tutto)
    o è cambiato solo il peso (aggiorno solo il peso)?
    Magari senza usare if (è cambiato peso){fai questo} else {fai quest'altro} ma
    usando una soluzione 'elegante' come il Polimorfismo?

    Scusate la lungaggine e vi ringrazio anticipatamente

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284

    Re: Observer - Quale variabile è cambiata

    Originariamente inviato da Gianpaolo69
    E qui riformulo la domanda:
    Nel metodo update, posso sapere se è cambiato solo il materiale (aggiorno tutto)
    o è cambiato solo il peso (aggiorno solo il peso)?
    Certo che si può fare, detto in generale. Ma devi stabilire tu come.

    Innanzitutto dalla tua classe SiloModel (che è il "subject" nella terminologia del pattern Observer) si evince che la notifica viene inviata in modo distinto se cambia il numero o il materiale o il peso. Insomma, una notifica è legata al cambiamento di una sola proprietà.

    Hai usato la implementazione dell'Observer fatta nel package java.util. Nota che il metodo update() di java.util.Observer ha un parametro Object arg che si può usare per fornire un qualche dato all'observer. E in Observable c'è un notifyObservers(Object arg), appunto per passare un qualche dato.

    Nel tuo caso potresti passare una stringa che indica la proprietà.

    codice:
    public void setNumero(Integer numero){
        this.numero=numero;
        setChanged();
        notifyObservers("numero");
    }
    E nel tuo observer:

    codice:
    public void update(Observable o, Object arg) {
        if (arg.equals("numero") {
            // è cambiato il numero ....
        ....
        else if (arg.equals("peso") {
            // è cambiato il peso ....
        ....
        ....
    }
    Ma se andiamo a vedere dal punto di vista concettuale, non sei nemmeno obbligato ad usare Observable/Observer di java.util. Quella è solo "una" implementazione del pattern Observer .... tra l'altro nemmeno perfetta poiché ha dei lati negativi (tanto per dirne una, Observable è una classe, non una interfaccia).

    I "model" che sono già esistenti in Swing (es. TableModel) ad esempio non usano affatto l'Observer di java.util. Usano i "listener" che comunque sono una forma molto "specializzata" del pattern Observer.

    Insomma ... per dirla in generale, non sei affatto obbligato a fare le cose in modo rigoroso o coerente con un qualche design pattern o architettura/libreria.

    Potresti addirittura fare un qualcosa di molto "accoppiato" tra il tuo SiloModel e SiloView.
    In SiloView potresti definire 3 metodi:

    public void updateNumero();
    public void updateMateriale();
    public void updatePeso();

    e in SiloModel mettere direttamente un riferimento ad 1 SiloView o se sai che ci possono essere più SiloView, mettere 2 metodi per (de)registrare i SiloView da notificare.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Innanzitutto grazie per la risposta, sempre molto chiara e professionale.

    Innanzitutto dalla tua classe SiloModel si evince che la notifica viene inviata in modo distinto se cambia il numero o il materiale o il peso. Insomma, una notifica è legata al cambiamento di una sola proprietà.
    Secondo te è buona regola fare in questo modo? Oppure ogni metodo set del model imposta
    solo il setChanged(), e che sia la View stessa a decidere quando notificare con model.notifyObservers();?

    Hai usato la implementazione dell'Observer fatta nel package java.util. Nota che il metodo update() di java.util.Observer ha un parametro Object arg che si può usare per fornire un qualche dato all'observer. E in Observable c'è un notifyObservers(Object arg), appunto per passare un qualche dato.

    Nel tuo caso potresti passare una stringa che indica la proprietà.

    codice:
    public void setNumero(Integer numero){
    this.numero=numero;
    setChanged();
    notifyObservers("numero");
    }

    E nel tuo observer:
    codice:

    public void update(Observable o, Object arg) {
    if (arg.equals("numero") {
    // è cambiato il numero ....
    ....
    else if (arg.equals("peso") {
    // è cambiato il peso ....
    ....
    ....
    }
    Questo vorrei evitarlo di fare. Una nidificazione di IF o SWITCH per capire chi è cambiato. Pensavo ad un qualcosa tipo un parametro polimorfo che nella View chiamasse il proprio metodo set() per aggiornare le label.

    Ma se andiamo a vedere dal punto di vista concettuale, non sei nemmeno obbligato ad usare Observable/Observer di java.util. Quella è solo "una" implementazione del pattern Observer .... tra l'altro nemmeno perfetta poiché ha dei lati negativi (tanto per dirne una, Observable è una classe, non una interfaccia).
    Questo mi sembra interessante. Dalla mia inesperienza posso intuire che Observable è una classe, quindi
    posso estendere la mia classe model una volta sola. Qual'è il vantaggio di avere un'interfaccia?

    Insomma ... per dirla in generale, non sei affatto obbligato a fare le cose in modo rigoroso o coerente con un qualche design pattern o architettura/libreria.
    Questo è ancora più interessante. Quindi secondo te è come se avessi carta bianca. Potrei utilizzare
    una mia implementazione del pattern Observer seguendo la regola di dotare il Subject di metodi
    che (de)registrano gli Observer ed utilizzare dei meccanismi di notifica personalizzati.
    Ed ancora. Ogni proprietà (numero, materiale, peso, etc) potrebbe addirittura essere essa stessa un model
    indipendente e, di conseguenza, alla View passare un array di model su cui registrarsi. Non so
    quanto convenga ma teoricamente è fattibile.
    Grazie ed un saluto

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 © 2025 vBulletin Solutions, Inc. All rights reserved.