简体   繁体   中英

Implementation of Observer Pattern Based on UML diagram

Question

I'm having trouble understanding the following UML-diagram of the Observer pattern from the "Elements of Reusable Object-Oriented Software". Could anyone explain me why my Java implementation is wrong and what I have to change to implement it correctly?

UML-Diagram

UML图

Attempted (but wrong) implementation

public interface Subject {
    
    public static final List<Observer> observers = new ArrayList<Observer>();
    
    public void attach(Observer o);
    public void detach(Observer o);
    public void notifyObservers();
}

public interface Observer { 
    public void update();
}

public class ConcreteSubject implements Subject {
    
    private String subjectState;

    @Override
    public void attach(Observer o) {
        observers.add(o);   
    }

    @Override
    public void detach(Observer o) {
        observers.remove(o);
    }

    @Override
    public void notifyObservers() {
        for (Observer o : observers) {
            o.update();
        }       
    }
    
    public String getState() {
        return subjectState;
    }
    
    public void setState() {
        subjectState += "x";
    }
}

public class ConcreteObserver implements Observer {
    
    private ConcreteSubject subject;
    public String observerState;

    @Override
    public void update() {
        observerState = subject.getState();
    }
}

One problem is that you have a static list of observers in Subject so all subjects share the same observers. However, the pattern requires that each individual subject has its own observers so put the list into ConcreteSubject and make it an instance field.

Another problem is that your ConcreteObserver has a field of type ConcreteSubject . It should, however, not know about the concrete implementation of Subject so the field should only have the type Subject .

Edit : Actually the UML diagram requires the concrete observer to know about the concrete subject in order to be able to call getState() so the above paragraph is not true in your case - this should not be a problem here.

However, in reality I would actually have another interface that extends Subject and hides the implementation of ConcreteSubject from the observer.

Edit 2 :

As has been suggested you could also use an abstract class to handle the observers of a subject. That could be a class in between Subject and ConcreteSubject or even Subject itself but since Java doesn't support multiple inheritance I'd often use some other approach and make Subject just an interface.

The easiest implementation would then be to have ConcreteSubject maintain the list of observers but in a real world application you'd not want to have developers do that or rely on them implementing it correctly.

Instead you could use a central registry that maintains the list of observers for each subject and which the subject uses to inform its observers. Many dependency injection frameworks out there operate in a way like that, ie whenever a "subject" changes they will inform its observers about that event.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM