Object Events, how do are they implemented
Events are really awesome, and I wouldn't know what I would do without them, but they're a mystery to me.
I'm talking about events in a sense, a function(s) is called if a property, or value, a special event happens.
I have only the vaguest idea how these actually work. 开发者_开发知识库I know it's an observer pattern, but I don't truly know how it works and/or how to implement it.
Can someone explain that to me?
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.
A simpel quick google brings
Observer pattern
And
Exploring the Observer Design Pattern
Events are actually very simple at a high level.
First, an Object defines an Event that other Objects can subscribe to. When an Object registers for an Event, the Object stores a function reference (or delegate) that will be called when the event happens.
Next, the interested Object subscribes to the event by passing a function reference to the Observable Object (the function must match the signature provided by the Observable class).
When the Event happens, the Observable class calls the appropriate method.
Here's a quick example (in 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());
}
}
And then in another class that wants to subscribe to the Changed event:
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
}
}
You need an interface(not neccesarily in the interface keyword sense of e.g. java/c#) to your observers - you need to somehow know which method to call when you need to notify them. The observers registers their interest and you add them to a list.
Every time you got something to notify, you go through the list of observers and call a method on each of them. When someone doesn't want to be notified any more, it's just a matter of removing them from your list of observers.
Here's a c# example without using the built in 'events' or delegates in 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();
}
}
}
精彩评论