2010-04-21 3 views
0

События действительно потрясающие, и я не знаю, что бы я сделал без них, но они для меня загадка.Объекты События, как они реализованы

Я говорю о событиях в некотором смысле, функция (функции) вызывается, если происходит свойство или значение специального события.

У меня есть только смутное представление о том, как они работают. Я знаю, что это шаблон наблюдателя, но я действительно не знаю, как это работает и/или как его реализовать.

Может кто-нибудь объяснить это мне?

+2

На каком языке? – bmargulies

+1

Не имеет значения. – Malfist

ответ

2

Как я понимаю, вы спрашиваете, как события работают под одеялом. Вы не указали, на каком языке/платформе вы спрашиваете, поэтому я собираюсь ответить тем, что знаю (.Net), хотя я уверен, что многие платформы похожи, помните, что то, что я говорю, может не быть истинно везде.

Я начну с самого низкого уровня и работаю вверх.

указатели на функции

В большинстве языков есть понятие указателя функции. В таких языках, как C++, вы можете буквально сохранить указатель на адрес памяти метода. В функциональных языках, таких как функции Lisp или F #, являются ключевыми, и это важная часть языка, на котором вы можете хранить и передавать ссылки на функции. В .net, указатели на функции реализуются с использованием делегатов.

Делегаты

В .Net мероприятия реализуются с помощью делегатов. A delegate - это указатель функции безопасного типа. Это указатель на функцию, которая ограничена определенным типом и проверяется на этот тип во время компиляции. Вы можете вызвать делегат, и он вызовет функцию, на которую указывает.

Multicast

multicast delegate это класс, который формирует коллекцию делегатов. Он использует внутренний список для хранения нескольких делегатов. Когда вы вызываете add или делаете +=, вы просто добавляете свой новый делегат (указатель функции) во внутренний список многоадресной рассылки. Многоадресные экземпляры делегатов могут запускаться, и он просто перемещается вниз по списку и запускает внутри каждого делегата в последовательности.

Событие

event только ключевое слово, которое добавляет несколько дополнительных ограничений на верхней части группового делегата, который подкрепляет событие. Например, с помощью ключевого слова event, когда вы объявляете экземпляр делегата многоадресной рассылки, он ограничивает его, чтобы он мог быть запущен только из класса, в котором он объявлен.

Итак, подведем итоги. События - это всего лишь список указателей на функции. Когда вы подписываетесь, вы просто добавляете указатель на свою функцию в список. Когда событие запускается, он просто перемещается вниз по списку и запускает каждый указатель функции, о котором он знает.

Очевидно, что, как я сказал в начале, каждый язык/среда будет отличаться, но я не удивлюсь, если идея поддержания простых списков указателей функций, вероятно, довольно распространена.

Джон Скит имеет отличную article on events in .Net, что вы должны читать для получения дополнительной информации, если это платформа вы заинтересованы.

0

События на самом деле очень просто на высоком уровне.

Во-первых, объект определяет событие, на которое могут подписаться другие объекты. Когда объект регистрируется для события, объект сохраняет ссылку на функцию (или делегат), которая будет вызываться, когда происходит событие.

Далее заинтересованный объект подписывается на событие, передавая ссылку функции на наблюдаемый объект (функция должна соответствовать сигнатуре, предоставляемой классом 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()); 
    } 
} 

А потом в другой класс, который хочет, чтобы подписаться на событие изменения:

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 
    } 
} 
+0

Хорошо, теперь низкий уровень (при условии, что это что-то интересное);) ... – FrustratedWithFormsDesigner

+1

@FrustratedWithFormsDesigner Это интересно ... но языки различаются в их реализациях. Все зависит от деталей, которые вы хотите. ;-) –

+0

Вы дали пример C#, поэтому давайте придерживаться этого ... на данный момент (хотя я смутно помню, что модель событий, что OS X, используемая с Objective-C, также казалась интересной;)) – FrustratedWithFormsDesigner

0

вам нужен интерфейс (не neccesarily в интерфейс ключевого слова, например, java/C#), вы должны как-то узнать, какой метод вызывать, когда вам нужно , чтобы уведомить об этом. Наблюдатели регистрируют их интерес, и вы добавляете их в список.

Каждый раз, когда у вас есть что сообщить, вы просматриваете список наблюдателей, а вызывают метод для каждого из них. Когда кто-то не хочет, чтобы вас больше не уведомляли, это просто вопрос их удаления из списка наблюдателей.

Вот с # пример без использования встроенного «событий» или делегатов в 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(); 
    } 
} 
} 
Смежные вопросы