События объекта, как они реализованы - PullRequest
0 голосов
/ 21 апреля 2010

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

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

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

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

Ответы [ 4 ]

2 голосов
/ 21 апреля 2010

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

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

Функциональные указатели

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

1012 * Делегаты *

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

Multicast

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

Событие

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

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

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

У Джона Скита есть отличная статья о событиях в .Net , которую вы должны прочитать для получения дополнительной информации, если интересует эта платформа.

2 голосов
/ 21 апреля 2010
0 голосов
/ 21 апреля 2010

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

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

Вот пример 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();
    }
}
}
0 голосов
/ 21 апреля 2010

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

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

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

Когда событие происходит, класс 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
    }
}
...