0

I am trying to learn Observer and publisher-subscriber pattern.

came through this simple example here

Problem: There is a button and onclick of the button it should be updating the count.

without any pattern i can do simply as

window.onload = function() {
  var container = document.querySelector('.container');
  var count = 0;
  container.querySelector('#click').addEventListener('click', function() {
    count = +document.querySelector("#count").innerHTML;
    count++;
    document.querySelector("#count").innerHTML = count;
  });
}
<div class="container">
  <input type="button" id="click" value="click">Total Counts: <span id="count">0</span>
</div>

In the above link that i have shared about observer pattern it has an implementation for the same using observer pattern jsbin

My Question here, is the usage of a pattern not complicating the code. I am really having a bad time of understanding what exactly the code is trying to solve .can some one please explain this and what is this.notify doing in the jsbin code.

Please help

Thanks

Geeky
  • 7,420
  • 2
  • 24
  • 50
  • well ... the `simple example` states that *The observer pattern is a simple way to allow communication between elements without having to rely on events, callbacks, or polling.* - but the jsbin you posted uses events, so the jsbin is no relevant to the simple example – Jaromanda X Jan 13 '17 at 01:05
  • the link that i have shared have a link to this jsbin...if that is not the right way,can you please explain how exactly we can use it here – Geeky Jan 13 '17 at 01:06
  • oops ... sorry, didn't see the onclick in the demo page ... seems like that demo page is self contradicting by using an event in code stated to not rely on events .... as the demo page itself is self contradictory, I couldn't possibly begin to "explain" how to use it, not even the author is able to do that !! – Jaromanda X Jan 13 '17 at 01:12
  • ok if that is the case can you give an example of an observer pattern usage it would be really helpful to me for understanding – Geeky Jan 13 '17 at 01:13
  • I just explained, that observer pattern page is self contradictory, I can't presume to know what it's author intended – Jaromanda X Jan 13 '17 at 01:14

4 Answers4

1

Not an expert in patterns but from what I understand, with simple code like your example that takes in a single event listener, the Observer Pattern would definitely be overkill.

As explained in your link above: "The observer pattern is a simple way to allow communication between elements without having to rely on events, callbacks, or polling. The best thing about the observer pattern is that the thing being observed does not have to worry about what is observing it or how many observers it has." It basically allows you to attach observers easily without having to modify the base element code, because the base code doesn't really have to care about who is watching it. It just has to announce that it's done something (increased a counter property) and it's up to the observers to react accordingly. Because of this, the counter code could stand on it's own and not have any dependencies to run (thus, making it easier to test as well). If you need to make changes to your observers, you won't have to touch the counter code and risk causing any side effects.

In comparison, your example has your callback code and counter heavily tied to one another. If you need to make a change like say, making it have different wording or have the counter value appear under a specific element, you have no choice but to touch that entire block of code. Again though, your code example is simple enough and if that is all it will be doing, then it should be perfectly fine to use.

I think it's easier to understand the concept of the Observer pattern when working with stuff like async code and Promises, where your callbacks/observers become separate from your implementing async code

georaldc
  • 1,880
  • 16
  • 24
1

Firstly, please make sure we are on the same page regarding the terminologies in Observer Pattern (OP): Observer object, Subject (or Observee) object, Subject.addObserver(...) method, and Subject.notify(...) method.

OK, now,

without any pattern i can do simply as

No, you are actually using OP in an implicit form. When you wrote:

container.querySelector('#click')

This will return a reference to the button, I name it button:

var button = container.querySelector('#click');

Then the call button.addEventListener(...) is basically an analogy to Subject.addObserver(...). This means that your button object is actually the Subject in OP. The call Subject.notify(...) is implicitly handled by the JavaScript engine. And your inline function to consume the click event is actually the Observer.

The main difference between your code and the code of jarrettmeyer.com lies in the question: who is the Subject? In jarrettmeyer.com, Subject is not any button but a separated object: the Counter object. This offers some advantages:

  1. The Subject can associate with many buttons, for example, jarrettmeyer can write: $("#anotherButton").on("click", function () { counter.increment(); });

  2. The Subject can easily maintain whatever state and notify whatever info to the Observer. In jarrettmeyer's example, these state/info are simply a count number. Indeed, in your example, no state/info of the button (except the fact that it has just been clicked) is notified since the count number is maintained in your span which belongs to the implementation detail of your Observer and thus not related to OP.

Nghia Bui
  • 3,694
  • 14
  • 21
1

Do you know the code you wrote is also an implementation of the observer pattern? The function you passed after the 'click' argument is an observer and it is added to the observers' array. You can add as many functions as you want against the 'click' event of the same element. They all will be fired by running a loop in the observers' array when the 'click' event happens.

If you have only one action happening as a response to some other action, you can write the action manually without implementing the observer pattern. However, when you want to do multiple things at multiple parts of the codebase in response to some event, observer pattern is the way to go.

Shakil Ahmed
  • 181
  • 1
  • 3
  • 13
0

Yes, you are right. addEventListener or jQuery .on() could do the similar thing as Observer. They are good enough for most of the front-end usage. But in the following use cases (backend/abstraction), observer pattern is better:

  1. The event being listened is not related to the DOM elements (e.g. JS object's mutation)

  2. You would like to have a better control on removeEventListener (e.g. multiple anonymous callback functions bound on an event type, you would like to move one of them)

The .notify method in the example is made to loop all the callback function in registry array, and try to execute all of them.

Here's a Codepen to show how observer help in the real world.

And here's a simple observer implementation when I learn Observer pattern:

var App = function() {
  // This array will store all the subscribers.
  this.subscribers = [];
}
// Subscribe, unsubscribe and publish are three base methods in this pattern
App.prototype.subscribe = function(subscriber) {
  this.subscribers.push(subscriber);
}
App.prototype.unsubscribe = function(subscriber) {
  for (var i = 0; i < this.subscribers.length; i++) {
    if (this.subscribers[i] === subscriber) {
      this.subscribers.splice(i, 1);
    }
  }
}
App.prototype.publish = function(message) {
  for (var i = 0; i < this.subscribers.length; i++) {
    console.log(this.subscribers[i] + ' got ' + message + '!');
  }
}
// Testing code.
var myApp = new App();
myApp.subscribe('Timmy');
myApp.subscribe('Tommy');
myApp.publish('a new magazine'); // Both Timmy & Tommy got the new magazine
myApp.unsubscribe('Timmy');
myApp.publish('a new book'); // Now only Tommy got the new book

Attached the Codepen for reference.

Eric Tan
  • 1,377
  • 15
  • 14