我最近一直在研究听众,我想我终于让他们失望了。基本上,它们是在另一个对象的方法上调用的函数。我的问题是,为什么在调用函数时创建一个事件监听器才能正常工作?
示例,我想调用player.display_health(),当触发它时,应该触发并存储方法player.get_health(),以便display_health()可以访问它。为什么我应该使用事件监听器而不是简单地调用该函数?即使display_health()在另一个对象中,这对我来说似乎也不是问题。
如果你有另一个更好地符合用法的例子,请告诉我。也许特定语言不能从中受益多少? (Javascript,PHP,ASP?)
答案 0 :(得分:11)
您可能无法始终控制正在执行调用的代码。或者即使您是,也不希望在该代码中引入依赖项。在这种情况下,代码最好触发一个事件并允许你控制的代码或应该具有依赖关系的代码来监听事件并采取相应的行动。
例如,您可能正在创建一个供其他人使用的库。他们没有源代码或以某种方式不能/不应该能够修改它(或者不应该)。您的文档说明在特定情况下会引发特定事件。然后,他们可以对这些事件作出回应。
或许您的企业中有一些域库。您可以控制它们并可以对它们进行修改,但从架构上来说,它们通常被认为是有效的,因为它们当前已编码且不应更改。 (不想招致一轮QA重新验证更新的代码,代码属于另一个部门,他们不希望你改变它等等。)你处于你想要的位置代码能够在不同的环境/环境中做不同的事情。如果该代码引发相关的事件和事件,您可以将代码挂钩(和/或相应地交换),而不必弄乱该代码。
只是几个简单的例子,我相信其他人有更多。
答案 1 :(得分:4)
我的问题是,为什么在调用函数时创建一个事件监听器才能正常工作?
如果您不知道要拨打什么功能怎么办?
采用经典示例,用户可以单击的按钮。无论是谁写了这个库都不知道当点击按钮时你想要调用什么函数。如果每个Button在单击时只能调用相同的函数,那么它也会非常令人望而却步。
因此,您可以将事件处理程序附加到事件。然后当事件被触发时,Button可以做它需要的东西,而不必在编译时确切地知道它应该调用什么函数。
答案 2 :(得分:1)
简而言之,您可以编写没有事件侦听器的代码,但使用事件侦听器帮助其他人使用与库相同的代码。
答案 3 :(得分:1)
即使有上面的详细解答,我仍然无法理解使用控制器/函数或事件监听器之间的实际差异。
所有这些答案中遗漏的一个问题是,当您不想如此密切地耦合代码时,使用事件和事件监听器会派上用场。每个函数,类等都应该具有单一目的。
所以说你受到了局外人的API请求。就我而言,我理解这个概念的确切问题是当我从Stripe Webhooks接收API调用时。
Stripe Webhooks的目的是:假设客户在您的网站上花费10,000美元。您的标准程序是Auth和Capture。更新数据库以反映其新的成员资格状态。在一个完美的世界,在我们公司的案例中,999/1000次,这是完美的。他们的卡片当场被拒绝,或付款通过。在这两种情况下,我们都会向他们发送一封电子邮件,让他们知道。
但是,当用户付费并且Stripe返回卡片失败错误(可能是许多不同的东西)的1/1000时间呢?在我们的例子中,我们通过电子邮件发送并告诉他们结算失败。我们遇到的问题是,有些银行正在调查大笔费用,这些费用会以错误形式返回,但几分钟后,银行会对收费进行授权并收取付款。
那有什么可做的?输入Stripe Webhooks。如果出现类似的情况,Stripe Webhooks将会遇到API端点。实际上,Stripe Webhooks可以随时点击您的API,并且每次付款都不会立即进行Authed,Captured或者客户要求退款。
这是事件监听器派上用场的地方。条纹使用客户信息以及Webhook类型在POST上进行拍摄。我们现在将处理,更新数据库,并向他们发送成功的电子邮件。
但为什么不使用标准路线和控制器? 我们不仅仅使用标准路由和控制器的原因是因为我们要么需要修改已定义的函数,类等,要么创建一系列耦合在一起的类,例如 - >接收的条带API调用,更新数据库,发送电子邮件。我们不是将这些紧密地耦合在一起,而是使用事件监听器首先接受API调用,然后点击每个类,函数等,使所有内容都解耦。
我到处寻找,我认为Laravel文档最好地解释了它。在给出一个具体的例子时,我终于明白了,事件监听器的目的是什么:
事件是解耦应用程序各个方面的好方法,因为单个事件可以有多个不依赖于彼此的侦听器。例如,您可能希望在每次订单发货时向您的用户发送Slack通知。您可以引发OrderShipped事件,而不是将您的订单处理代码与Slack通知代码相关联,侦听器可以接收该事件并将其转换为Slack通知。
答案 4 :(得分:1)
我认为事件与函数调用的主要原因是,事件是“ 已监听”,而调用是“ 进行”。因此,总是对另一个对象进行函数调用,而侦听器“ 选择”侦听要从您的对象广播的事件。 观察者模式是对此功能的很好研究。这是一个简短的node.js示例,它说明了这一概念:
var events = require('events');
var Person = function(pname) {
var name = pname;
};
var james = new Person('james');
var mary = new Person('mary');
var loudmouth = new Person('blabberer');
loudmouth.mouth = new events.EventEmitter();
//jame's observer.
james.read_lips = function(msg){
console.log("james found out: " + msg);
};
//james adds his event to the emitter's event listener.
james.enter_elevator = function(){
console.log('james is in the elevator');
//NOTE: james adds HIMSELF as a listener for the events that may
//transpire while he is in the elevator.
loudmouth.mouth.on('elevator gossip', james.read_lips)
};
//james removes his event from the emitter when he leaves the elevator.
james.leave_elevator = function(){
// read lips is how james responds to the event.
loudmouth.mouth.removeListener('elevator gossip', james.read_lips);
console.log('james has left the elevator');
};
//mary's observer
mary.overhear = function(msg){
console.log("mary heard: " + msg);
};
//mary adds her observer event to the emitter's event listeners
mary.enter_elevator = function(){
// overhear is how mary responds to the event.
console.log('mary is in the elevator');
//NOTE: now mary adds HERSELF to the listeners in the elevator and
//she observes using a different method than james which suits her.
loudmouth.mouth.on('elevator gossip', mary.overhear);
};
loudmouth.speaks = function(what_is_said){
console.log('loudmouth: ' + what_is_said);
this.mouth.emit('elevator gossip', what_is_said);
};
james.enter_elevator();
mary.enter_elevator();
loudmouth.speaks('boss is having an affair');
james.leave_elevator();
loudmouth.speaks('just kidding');
console.log('james did not hear the last line because he was not listening anymore =)');
因此,在这个“故事”中,演员选择收听或何时不收听来自第三方的事件。我希望这会有所帮助。