Is there any technical reason for the Observer pattern or the like not being used independently of the observed object?

10

We often use things we do not even think about because it's like this.

I do not like to place mechanism pendants on an object that is domain specific.

If I have a screen control or a client that has some action that triggers an event my normal is to use some form of event where the object has a list of subscribers that obviously grows as it is taking interested objects (observers) in any change of state or behavior that this observed object is willing to warn that has occurred, is occurring or will occur. The control mechanism stays on this object and has the cost in it.

I wondered if it was not more interesting to have a separate observation object, then this object that was observed tells the observation object that it has available events and the observing objects sign those desired events. All this object is responsible for the mechanism of observation and the objects that communicate do not have their own mechanisms reducing their responsibility, apparently improving the cohesion and coupling.

I am mainly concerned with the object load state that is not part of the domain of it. I know it's priceless in many cases and I should not worry too much about it. But the question remains whether from the strict engineering point of view it makes sense to do something like this.

I do not want to know which one is the best, but if I'm looking at the overall picture properly or missed something important.

Illustrative example only simplified and naively in pseudocode:

class Score
    value = 0
    Increase() {
        value++
        Changed(this)
    }
    Score() {
        RegisterEvent(this, Increase)
    }
    ~Score() {
        UnregisterEvent(this, Increase)
    }

class Observation {
    observables[] = new[]
    RegisterEvent(obj, method) {
        observables[obj << ptrLength + method] = new[]
    }
    UnregisterEvent(obj, method) {
        observables[obj << ptrLength + method] = null
    }
    SubscribeEvent(obj, method, action) {
        observables[obj << ptrLength + method] += action
    UnsubscribeEvent(obj, method, action) {
        observables[obj << ptrLength + method] -= action
    }
}
class App {
    static player1 = new Score()
    static player2 = new Score()
}
class Screen {
    Screen() {
        SubscribeEvent(player1, Score.Increase, PaintScore1) {
        SubscribeEvent(player2, Score.Increase, PaintScore2) {
    }
    ~Screen() {
        UnsubscribeEvent(player1, Score.Increase, PaintScore1) {
        UnsubscribeEvent(player2, Score.Increase, PaintScore2) {
    }
    PaintScore1(obj) { ... }
    PaintScore2(obj) { ... }
}
class Fire {
    ...
    Reached(player) {
        (player == 1 ? player1 : player2).Increase()
    }
}

Would this be the same as the Mediator standard? If so, would Mediator be a replacement for the Observer? Or they serve different purposes. With the advent of Mediator would the Observer be obsolete? Or do they complement each other? Or would it be wrong for them to complement each other?

Would this be the Event Aggregator? And is this just one of the many things I thought I invented? Dammit Fowler! : P

    
asked by anonymous 30.07.2018 / 15:16

1 answer

2
  

Is there any technical reason for the Observer pattern or similar not being used independently of the observed object?

From the point of view of cohesion and coupling, both the Subject and the Observers are independent, ie the functioning and responsibility of a subject does not depend on observers, and no matter what the type and specialization of the objects involved, everyone only has to respect a "contract" (interface) for example.

Illustrative example:

Interface Observer

public interface Observer {

    void onStateChanged(String attribute, Object oldValue, Object newValue);    
}

Interface Subject

public interface Subject {

    void addObserver(Observer observer);

    void removeObserver(Observer observer); 
}

An "Observable" class

public class Bird implements Subject {

    private List<Observer> observers = new ArrayList<>();
    private boolean flying;

    public boolean isFlying() {
        return flying;
    }

    public void setFlying(boolean flying) {
        boolean oldValue = this.flying;
        this.flying = flying;
        notifyObservers("flying", oldValue, this.flying);
    }

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);     
    }

    private void notifyObservers(String attribute, Object oldValue, Object newValue) {
        observers.forEach(o -> o.onStateChanged(attribute, oldValue, newValue));
    }       
}

An "Observer" class

public class BirdObserver implements Observer {

    @Override
    public void onStateChanged(String attribute, Object oldValue, Object newValue) {
        System.out.println(String.format("%s %s %s", attribute, oldValue, newValue));       
    }
}

Note that even with a 1xN relation, the cost (Pub / Sub) is quite low, I do not see the pub / sub mechanism outside the scope of an "observable" object.

So I do not believe there's a technical reason this does not happen separately in the Observer Pattern.

Now, your proposal bears a certain resemblance to two other patterns:

So why not apply them in all cases where you need a pub / sub mechanism?

As I said earlier, the cost of the Observer does not have a significant impact on cohesion and coupling, if you have a simple application that needs pub / sub, this pattern resolves smoothly.

Now, imagine an application that has more than 100 Observables (with multiple types of events) and more than 100 Observers. To make it a bit more complex, imagine that some of these objects need a notion of NxN states. It would be a bit complex to manage this with just the Observer. In this case you could enter the role of a "centralizer" to manage the exchange of messages between all, and that's where the Mediator or Event Aggregator comes in.

Therefore,

  

Would this be the same as the Mediator standard?

Very similar proposal.

  

If it is, would Mediator be a substitute for the Observer? Or they serve different purposes.

No, one does not replace the other. They have similarities in facilitating communication between objects.

  

With the advent of Mediator would the Observer be obsolete? Or do they complement each other? Or would it be wrong for them to complement each other?

Also, the mediator does not make observer obsolete. They can be used independently or can complement each other, depending on the scenario applied.

  

Would this be the Event Aggregator?

It's a bit similar too.

  

And is this just one of the many things I thought I invented?

Apparently yes, sorry. = P

    
05.08.2018 / 15:53