事件真的很棒,我不知道没有它们我会做什么,但它们对我来说是个谜。
我说的是某种意义上的事件,如果属性或值发生特殊事件,则调用函数。
我只有最模糊的想法这些实际上是如何工作的。我知道这是一种观察者模式,但我并不真正知道它是如何工作的和/或如何实现它。
有人可以向我解释吗?
事件真的很棒,我不知道没有它们我会做什么,但它们对我来说是个谜。
我说的是某种意义上的事件,如果属性或值发生特殊事件,则调用函数。
我只有最模糊的想法这些实际上是如何工作的。我知道这是一种观察者模式,但我并不真正知道它是如何工作的和/或如何实现它。
有人可以向我解释吗?
As I understand it you are asking how events work under the covers. You haven't specified which language/platform you are asking about so I'm going to answer with what I know (.Net), although I'm sure a lot of platforms are similar bear in mind that what I say might not be true everywhere.
I'll start from the lowest level and work upwards.
Function pointers
In most languages there is the concept of a function pointer. In languages like C++ you can literally store a pointer to the memory address of a method. In functional languages like Lisp or F# functions are key and it's a crucial part of the language that you can store and pass function references around. In .net, function pointers are implemented using delegates.
Delegates
In .Net events are implemented using delegates. A delegate is a type safe function pointer. It's a pointer to a function, that is restricted to a specific type, and checked against that type at compile time. You can trigger the delegate and that will call the function it points to.
Multicast
A multicast delegate is a class that forms a collection of delegates. It uses a list internally to store multiple delegates. When you call add
or do +=
you are just adding your new delegate (function pointer) into the multicast's internal list. Multicast delegate instances can be triggered and it simply moves down the list and triggers internally each delegate in sequence.
Event
An event is just a keyword that adds a few extra restrictions on top of the multicast delegate that underpins the event. For example (amongst other things) by using the event keyword when you declare the multicast delegate instance it restricts it so that it can only be triggered from within the class it is declared in.
So, to sum up. Events are just a list of function pointers. When you subscribe you simple add a pointer to your function to the list. When the event is triggered it simply moves down the list and triggers each function pointer it knows about.
Obviously, like I said at the start, every language/environment will differ, but I wouldn't be surprised if the idea of maintaining a simple lists of function pointers is probably fairly common.
Jon Skeet has an excellent article on events in .Net that you should read for more information if this is the platform you are interested in.
您需要一个接口(不一定在接口关键字意义上,例如 java/c#)给您的观察者——您需要以某种方式知道当您需要通知他们时要调用哪个方法。观察者注册他们的兴趣,然后您将他们添加到列表中。
每次你有东西要通知时,你都会遍历观察者列表并在每个观察者上调用一个方法。当某人不想再收到通知时,只需将其从您的观察者列表中删除即可。
这是 ac# 示例,没有使用 c# 中的内置“事件”或委托:
using System;
using System.Collections.Generic;
namespace ObserverTest
{
interface IInvestor
{
void Update(Stock stock);
}
abstract class Stock
{
private string _symbol;
private double _price;
private List<IInvestor> _investors = new List<IInvestor>();
// Constructor
public Stock(string symbol, double price)
{
this._symbol = symbol;
this._price = price;
}
public void Attach(IInvestor investor)
{
_investors.Add(investor);
}
public void Detach(IInvestor investor)
{
_investors.Remove(investor);
}
public void Notify()
{
foreach (IInvestor investor in _investors)
{
investor.Update(this);
}
Console.WriteLine("");
}
public double Price
{
get { return _price; }
set
{
if (_price != value)
{
_price = value;
Notify();
}
}
}
public string Symbol
{
get { return _symbol; }
}
}
class IBM : Stock
{
public IBM(string symbol, double price)
: base(symbol, price)
{
}
}
class Investor : IInvestor
{
private string _name;
// Constructor
public Investor(string name)
{
this._name = name;
}
public void Update(Stock stock)
{
Console.WriteLine("Notified {0} of {1}'s " +
"change to {2:C}", _name, stock.Symbol, stock.Price);
}
}
class MainApp
{
static void Main()
{
IBM ibm = new IBM("IBM", 120.00);
ibm.Attach(new Investor("Sorros"));
ibm.Attach(new Investor("Berkshire"));
ibm.Price = 120.10;
ibm.Price = 121.00;
ibm.Price = 120.50;
ibm.Price = 120.75;
Console.ReadKey();
}
}
}
事件在高层次上实际上非常简单。
首先,一个对象定义了一个其他对象可以订阅的事件。当一个对象注册一个事件时,对象存储了一个函数引用(或委托),当事件发生时将调用该函数引用。
接下来,感兴趣的 Object 通过将函数引用传递给 Observable Object 来订阅事件(该函数必须与 Observable 类提供的签名匹配)。
当事件发生时,Observable 类调用适当的方法。
这是一个简单的示例(在 C# 中):
// Specifies the signature for the event and stores the reference
public delegate void ChangedEventHandler(object sender, EventArgs e);
public class ObservableObject
{
// Creates an event called Changed using the signature provided by the
// delegate.
public event ChangedEventHandler Changed;
// This is the method we're interested in notifying subscribers about.
public void SomeInterestnigMethod()
{
// Something just changed, notify subscribers
Changed(this, new EventArgs());
}
}
然后在另一个想要订阅 Changed 事件的类中:
public class Observer
{
ObservableObject _obj = new ObservableObject();
public Observer()
{
// Pass the function reference to objChangedHandler to the
// Observable Object.
_obj.Changed += objChangedHandler;
}
public void objChangedHandler(object sender, EventArgs e)
{
// Handle the event here
}
}