lundi 8 juin 2015

Some doubts about the interpretation of an interface driven implementation of the observer pattern in Java

I am studying the observer pattern implemented in Java and I have some doubts about how the tutorial implementation exactly works.

So I know that this pattern is used in all the situation that expect the user interation with a GUI (for example the user click on a button) or all the situation in which an event happen at an unpredictable time (like a timer, when the timer snap an event have to be handled).

So I know that in the observer pattern are involved 2 differents type of object:

  1. The subject object: that is the object on which something happen at an unpredictable time (for example a button that could be clicked in any time by the user)

  2. The observer object (or listener): it seems to me that it contains the code that is performed when something change into the subject object (for example it handle the click of my button). Is it true or am I missing something? I am absolutly not true about this statment...I have the doubt that maybe the observer object have only to listen the change on the subject and perform an operation on the subject when this change happens. For example: the button (th subject) is clicked, the observer listen to it and discover this change and so it perform a specific operation on the subject (perform a specific method on the subject object).

What is the correct interpretation? The observer listen the subject change and perform an operation defined into the observer or perform an operation defined into the subject?

I know that to do it I can pass a reference of the subject to the observer (so I think that the operation performed is defined into the subject...) but this is a bad practice because it involve a form of tight coupling between subject and observer so I know that exist an interface driven solution but I have some difficulties to figure it out.

The tutorial make this example that represent a view that use Swing to render 2 buttons:

package com.caveofprogramming.designpatterns.demo1.view;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

import com.caveofprogramming.designpatterns.demo1.model.Model;

public class View extends JFrame implements ActionListener {

    private Model model;

    private JButton helloButton;        // SUBJECT OBJECT: l'oggetto su cui avviene l'evento
    private JButton goodbyeButton;      // SUBJECT OBJECT: l'oggetto su cui avviene l'evento

    public View(Model model) {
        super("MVC Demo");

        this.model = model;

        // Crea i 2 bottoni definiti sopra:
        helloButton = new JButton("Hello!");
        goodbyeButton = new JButton("Goodbye!");

        // Setta il layout manager da usare che stabilisce come sono posizionati gli elementi:
        setLayout(new GridBagLayout());

        GridBagConstraints gc = new GridBagConstraints();
        gc.anchor = GridBagConstraints.CENTER;
        gc.gridx=1;
        gc.gridy=1;
        gc.weightx=1;
        gc.weighty=1;
        gc.fill=GridBagConstraints.NONE;

        add(helloButton, gc);   // Aggiunge helloButton dentro il layout

        gc.anchor = GridBagConstraints.CENTER;
        gc.gridx=1;
        gc.gridy=2;
        gc.weightx=1;
        gc.weighty=1;
        gc.fill=GridBagConstraints.NONE;

        add(goodbyeButton, gc); // Aggiunge goodbyeButton dentro il layout

        helloButton.addActionListener(this);
        goodbyeButton.addActionListener(this);

        goodbyeButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Sorry to see you go.");
            }

        });

        setSize(600, 500);                          // Setta le dimensioni della finestra
        setDefaultCloseOperation(EXIT_ON_CLOSE);    // Setta il comportamento di cosa succede premendo il tasto X
        setVisible(true);                           // Setta la finestra come visibile
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        JButton source = (JButton)e.getSource();

        if(source == helloButton) {
            System.out.println("Hello there!");
        }
        else {
            System.out.println("Some other button.");
        }

    }   

}

So in this example I have 2 buttons that represent my subject objects, these:

private JButton helloButton;        
private JButton goodbyeButton;

The View class implements an ActionListener interface (so I think that it is the interface mentioned earlier, is it true?)

Looking inside the ActionListener.class I found:

// Method descriptor #8 (Ljava/awt/event/ActionEvent;)V public abstract void actionPerformed(java.awt.event.ActionEvent arg0);

So this is a method that have to be implemented and this is the method that is invoked when an action occurs and I have to implement it, this:

@Override
public void actionPerformed(ActionEvent e) {

    JButton source = (JButton)e.getSource();

    if(source == helloButton) {
        System.out.println("Hello there!");
    }
    else {
        System.out.println("Some other button.");
    }

}

So the actionPerformed() method is implemented into the View class because it extend the ActionListener interface and it handle the click of the buttons.

So my first doubt is: is the ActionListener interface implementation my observer object? And so it means that the View* class contains the **subject objects (my buttons) but it is also a observer/listener implementation?

To add the listerner (the observer object) to a button I do:

helloButton.addActionListener(this);

and I pass this because the class that contains the observer is the same of the one where the subject objects are defined. Is it correct?

So it is a best practice because I boundle togheter the subject with the observer into a single class and I have not tight coupling derived by a reference of the subject inside the observer?

Is it my reasoning correct or am I missing something?

Aucun commentaire:

Enregistrer un commentaire