dimanche 4 octobre 2015

Observer pattern - does the observer needs to know the Subject ?

I'm trying to understand the observer pattern , this is a simple code that I picked online :

import java.util.ArrayList;
import java.util.List;


/**
 * The observer pattern is a software design pattern in which an object, 
 * called the subject, maintains a list of its dependents, called observers, and 
 * notifies them automatically of any state changes, usually by calling one of their methods
 * @author X220
 *
 */


interface Subject 
{
    // methods to register and unregister observers
    public void register(Observer obj);

    public void unregister(Observer obj);

    // method to notify observers of change
    public void notifyObservers();

    // method to get updates from subject
    public Object getUpdate(Observer obj);
}

interface Observer 
{
    // method to update the observer, used by subject
    public void update();

    // attach with subject to observe
    public void setSubject(Subject sub);
}

/**
 * Holds a list of the observers
 * @author X220
 *
 */
class MySubject implements Subject 
{
    private List<Observer> observers;
    private String message;
    private boolean changed;
    private final Object MUTEX = new Object();

    public MySubject() 
    {
        this.observers = new ArrayList<>();
    }

    @Override
    public void register(Observer obj) 
    {
        if (obj == null)
            throw new NullPointerException("Null Observer");
        synchronized (MUTEX) {
            if (!observers.contains(obj))
                observers.add(obj);
        }
    }

    @Override
    public void unregister(Observer obj) 
    {
        synchronized (MUTEX) 
        {
            observers.remove(obj);
        }
    }

    @Override
    public void notifyObservers() 
    {
        List<Observer> observersLocal = null;
        // synchronization is used to make sure any observer registered after
        // message is received is not notified
        synchronized (MUTEX) 
        {
            if (!changed)
            {
                return;
            }
            observersLocal = new ArrayList<>(this.observers);
            this.changed = false;
        }
        for (Observer obj : observersLocal) 
        {
            obj.update();
        }
    }

    @Override
    public Object getUpdate(Observer obj) {
        return this.message;
    }

    // method to post message to the topic
    public void postMessage(String msg) {
        System.out.println("Message Posted to Topic:" + msg);
        this.message = msg;
        this.changed = true;
        notifyObservers();
    }

}

class MyObserver implements Observer 
{
    private String name;
    private Subject topic;

    public MyObserver(String nm) {
        this.name = nm;
    }

    @Override
    public void update() {
        String msg = (String) topic.getUpdate(this);
        if (msg == null) {
            System.out.println(name + ":: No new message");
        } else
            System.out.println(name + ":: Consuming message::" + msg);
    }

    @Override
    public void setSubject(Subject sub) {
        this.topic = sub;
    }

}


public class RunCode1 
{

    public static void main1(String[] args) {
        // create subject
        MySubject topic = new MySubject();

        // create observers
        Observer obj1 = new MyObserver("Obj1");
        Observer obj2 = new MyObserver("Obj2");
        Observer obj3 = new MyObserver("Obj3");

        // register observers to the subject
        topic.register(obj1);
        topic.register(obj2);
        topic.register(obj3);

        // attach observer to subject
        obj1.setSubject(topic);
        obj2.setSubject(topic);
        obj3.setSubject(topic);

        // check if any update is available
        obj1.update();

        // now send message to subject
        topic.postMessage("New Message");
    }
}

Pretty much I got the idea , but one thing bothers me : the Observer has a setSubject() method , and he himself( the observer) also registers to subject and also sets the Subject , which seems to me a little bit wrong .

I can change the interface and remove the setSubject() method , however my question is do I really need also to set a subject after registering , from the Observer pattern point of view ?

Aucun commentaire:

Enregistrer un commentaire