I'm trying to learn Observer Design Pattern and I started to watch the series which belongs to codewithmosh called "The Ultimate Design Pattern Series".
in the lesson which was about Observer, he says:
This is what we call a "Push" style of communication. because the "Subject" pushes the changes to the observers.
However, there is a problem with this approach. Tomorrow, we might introduce a new type of ConcreteObserver and that observer might need a different set of values. So we have to come back here and change the Observer interface; we may have to introduce a new parameter, or we may have to change the object that is passed over here. we have to introduce new fields in that class.
So this approach is not very flexible, because the Subject is making assumptions about these Observers; it's assuming that these Observers need these values when a change happens. Now, what if each observer needs a different set of values? So, that is when we can use a "Pull" style of communication.
I'm just trying to understand why Push style is not flexible. my question is about this sentence:
So we have to come back here and change the Observer interface; we may have to introduce a new parameter, or we may have to change the object that is passed over here. we have to introduce new fields in that class.
this is my ConcreteSubject:
public class ConcreteSubject extends Subject {
private int value;
private String value2;
public void setValue(int value) {
this.value = value;
notifyObservers(value, null);
}
public void setValue2(String value2) {
this.value2 = value2;
notifyObservers(null, value2);
}
}
I also have 2 ConcreteObserver but ConcreteObserver2 doesn't want to be notified about the first field "value" in ConcreteSubject. I tried to introduce a new parameter like this:
public interface Observer {
<T, U> void update(T value, U value2);
}
and these are my other classes:
public class Subject { // Observable
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public <T, U> void notifyObservers(T value, U value2) {
for (Observer observer : observers)
observer.update(value, value2);
}
}
--
public class ConcreteObserver1 implements Observer {
@Override
public <T, U> void update(T value, U value2) {
if (value != null)
System.out.println("ConcreteObserver1 got notified. " + value);
if (value2 != null)
System.out.println("ConcreteObserver1 got notified. " + value2);
}
}
--
public class ConcreteObserver2 implements Observer {
@Override
public <T, U> void update(T value, U value2) {
if (value2 != null)
System.out.println("ConcreteObserver2 got notified. value2 is: " + value2);
}
}
So this was the first solution which the teacher talked about and that was introducing a new parameter and this was my implementation for this solution but I cannot understand the second solution. (the bold text)
what does it mean when he says "we may have to change the object that is passed over here"? I think it's useless because my parameter's type in the interface is generic and I can pass anything that I want. also I cannot understand "we have to introduce new fields in that class". in which class? why? how this can helps ConcreteObserver2 to be notified about a specific field?

If your design depends on what the observers need to know about the message, you should use the pulling style. Because there is always a possibility to change the contract of messages for the sake of observers. In other words, your message contract depends on the observers because they consume the message. In this way, changing observers' (consumers') requirements results in changing the message contract which is not a good coupling. The consumer's side is more likely to be changed. Because there are likely to be new consumers and existing consumers probably will change over time.
Observer design pattern should be used when the message contract depends on the Subject. In this notion, the subject dictates what the message contract structure is. For example, it's a good fit to use it with events. Events indicate that something happened. They don't care who uses this data, they are just broadcasting the event data.