简体   繁体   English

为什么要在这里使用Observer / Pub-Sub模式?

[英]Why should we use Observer/Pub-Sub pattern here?

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 在上面分享的关于观察者模式的链接中,它具有使用观察者模式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. 我真的很难理解代码到底想解决什么。可以请人解释一下这是什么,请在jsbin代码中做这件事。

Please help 请帮忙

Thanks 谢谢

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 我认为在使用异步代码和Promises之类的东西时,更容易理解Observer模式的概念,其中您的回调/观察者与实现异步代码是分开的

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. 首先,请确保我们关于Observer模式的术语(OP)在同一页上: Observer对象, Subject (或Observee )对象, Subject.addObserver(...)方法,并Subject.notify(...)方法。

OK, now, 现在可以,

without any pattern i can do simply as 没有任何模式,我可以简单地做为

No, you are actually using OP in an implicit form. 不,您实际上是在以隐式形式使用OP。 When you wrote: 当你写:

container.querySelector('#click')

This will return a reference to the button, I name it button : 这将返回对按钮的引用,我将其命名为button

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

Then the call button.addEventListener(...) is basically an analogy to Subject.addObserver(...) . 然后,调用button.addEventListener(...)基本上类似于Subject.addObserver(...) This means that your button object is actually the Subject in OP. 这意味着您的button对象实际上是OP中的Subject The call Subject.notify(...) is implicitly handled by the JavaScript engine. 调用Subject.notify(...)由JavaScript引擎隐式处理。 And your inline function to consume the click event is actually the Observer . 消耗click事件的内联函数实际上是Observer

The main difference between your code and the code of jarrettmeyer.com lies in the question: who is the Subject ? 您的代码与jarrettmeyer.com的代码之间的主要区别在于以下问题:谁是Subject In jarrettmeyer.com, Subject is not any button but a separated object: the Counter object. 在jarrettmeyer.com中,“ Subject不是任何按钮,而是一个单独的对象: Counter对象。 This offers some advantages: 这提供了一些优点:

  1. The Subject can associate with many buttons, for example, jarrettmeyer can write: $("#anotherButton").on("click", function () { counter.increment(); }); Subject可以与许多按钮关联,例如jarrettmeyer可以编写: $("#anotherButton").on("click", function () { counter.increment(); });

  2. The Subject can easily maintain whatever state and notify whatever info to the Observer . Subject可以轻松维护任何状态,并将任何信息通知Observer In jarrettmeyer's example, these state/info are simply a count number. 在jarrettmeyer的示例中,这些状态/信息只是一个count 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. 的确,在您的示例中,没有通知按钮的状态/信息(除了刚刚单击按钮的事实),因为count数值保留在您的span ,这属于您的Observer的实现细节,因此与OP不相关。

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. 您在“ click”参数之后传递的函数是观察者,并将其添加到观察者的数组中。 You can add as many functions as you want against the 'click' event of the same element. 您可以针对同一元素的“ click”事件添加任意数量的函数。 They all will be fired by running a loop in the observers' array when the 'click' event happens. 当“ click”事件发生时,所有这些都将通过在观察者数组中运行循环来触发。

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. 但是,当您想在代码库的多个部分上执行多项操作以响应某些事件时,观察者模式是您的理想之选。

Yes, you are right. 是的,你是对的。 addEventListener or jQuery .on() could do the similar thing as Observer. addEventListener或jQuery .on()可以执行与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 (eg JS object's mutation) 正在监听的事件与DOM元素无关(例如JS对象的变异)

  2. You would like to have a better control on removeEventListener (eg multiple anonymous callback functions bound on an event type, you would like to move one of them) 您希望对removeEventListener有更好的控制(例如,绑定在事件类型上的多个匿名回调函数,您想移动其中一个)

The .notify method in the example is made to loop all the callback function in registry array, and try to execute all of them. .notify中的.notify方法用于循环注册表数组中的所有回调函数,并尝试执行所有回调函数。

Here's a Codepen to show how observer help in the real world. 这是一个Codepen ,展示观察者如何在现实世界中提供帮助。

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. 随附Codepen以供参考。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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