<?xml version='1.0' encoding="utf-8"?>
      <rss version='2.0'>
      <channel>
      <title>Форум на Исходниках.RU</title>
      <link>https://forum.sources.ru</link>
      <description>Форум на Исходниках.RU</description>
      <generator>Форум на Исходниках.RU</generator>
  	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3082064</guid>
        <pubDate>Tue, 21 Feb 2012 13:51:46 +0000</pubDate>
        <title>События с несколькими слушателями</title>
        <link>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3082064</link>
        <description><![CDATA[--Ins--: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=351274&view=findpost&p=3081707'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>jack128 &#064; <time class="tag-quote__quoted-time" datetime="2012-02-21T12:11:17+04:00">21.02.12, 08:11</time></span><div class='quote '>TDelegate&lt;T&gt; не мешало бы наследником TEnumerable&lt;T&gt; сделать</div></div><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=351274&view=findpost&p=3081751'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Shaggy &#064; <time class="tag-quote__quoted-time" datetime="2012-02-21T10:02:55+00:00">21.02.12, 10:02</time></span><div class='quote '>TEqualityComparer&lt;EventType&gt;.Default.Equals(A,B)</div></div><br>
<br>
Угу, согласен]]></description>
        <author>--Ins--</author>
        <category>Все языки: Статьи, заготовки в FAQ</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3081751</guid>
        <pubDate>Tue, 21 Feb 2012 10:02:55 +0000</pubDate>
        <title>События с несколькими слушателями</title>
        <link>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3081751</link>
        <description><![CDATA[Shaggy: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=351274&view=findpost&p=3080753'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>&#045;&#045;Ins&#045;&#045; &#064; <time class="tag-quote__quoted-time" datetime="2012-02-19T17:27:10+00:00">19.02.12, 17:27</time></span><div class='quote '>Хм, так не пробовал, компилятор пропускает? Тоже не совсем то чего хотелось бы, если честно, а хотелось бы if a = b</div></div><br>
TEqualityComparer&lt;EventType&gt;.Default.Equals(A,B)<br>
<br>
?]]></description>
        <author>Shaggy</author>
        <category>Все языки: Статьи, заготовки в FAQ</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3081707</guid>
        <pubDate>Tue, 21 Feb 2012 08:11:17 +0000</pubDate>
        <title>События с несколькими слушателями</title>
        <link>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3081707</link>
        <description><![CDATA[jack128: TDelegate&lt;T&gt; не мешало бы наследником TEnumerable&lt;T&gt; сделать]]></description>
        <author>jack128</author>
        <category>Все языки: Статьи, заготовки в FAQ</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3080766</guid>
        <pubDate>Sun, 19 Feb 2012 17:56:37 +0000</pubDate>
        <title>События с несколькими слушателями</title>
        <link>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3080766</link>
        <description><![CDATA[--Ins--: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=351274&view=findpost&p=3080761'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>ViktorXP &#064; <time class="tag-quote__quoted-time" datetime="2012-02-19T17:53:07+00:00">19.02.12, 17:53</time></span><div class='quote '>так как TMethod имеет размер 8 байт то его можно привести к UInt64/Int64, но это будет не правильно так как в EventType можно положить тип больший/меньший по размеру и что в последствии приведет к ошибке.</div></div><br>
<br>
Не надо так делать, пусть это просто будет очередным примером &quot;сырости&quot; дельфийских дженериков. И ограничение, что тип должен быть метод, сделать не могу, и операция сравнения в пролете]]></description>
        <author>--Ins--</author>
        <category>Все языки: Статьи, заготовки в FAQ</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3080761</guid>
        <pubDate>Sun, 19 Feb 2012 17:53:07 +0000</pubDate>
        <title>События с несколькими слушателями</title>
        <link>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3080761</link>
        <description><![CDATA[ViktorXP: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=351274&view=findpost&p=3080753'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>&#045;&#045;Ins&#045;&#045; &#064; <time class="tag-quote__quoted-time" datetime="2012-02-19T17:27:10+00:00">19.02.12, 17:27</time></span><div class='quote '>Хм, так не пробовал, компилятор пропускает?</div></div><br>
да. пропустит. про это как в доке написано так и на своей практике использую.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=351274&view=findpost&p=3080753'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>&#045;&#045;Ins&#045;&#045; &#064; <time class="tag-quote__quoted-time" datetime="2012-02-19T17:27:10+00:00">19.02.12, 17:27</time></span><div class='quote '>Тоже не совсем то чего хотелось бы, если честно, а хотелось бы if a = b</div></div><br>
так как TMethod имеет размер 8 байт то его можно привести к UInt64/Int64, но это будет не правильно так как в EventType можно положить тип больший/меньший по размеру и что в последствии приведет к ошибке.]]></description>
        <author>ViktorXP</author>
        <category>Все языки: Статьи, заготовки в FAQ</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3080753</guid>
        <pubDate>Sun, 19 Feb 2012 17:27:10 +0000</pubDate>
        <title>События с несколькими слушателями</title>
        <link>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3080753</link>
        <description><![CDATA[--Ins--: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=351274&view=findpost&p=3080677'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>ViktorXP &#064; <time class="tag-quote__quoted-time" datetime="2012-02-19T13:56:34+00:00">19.02.12, 13:56</time></span><div class='quote '>А если так:</div></div><br>
<br>
Хм, так не пробовал, компилятор пропускает? Тоже не совсем то чего хотелось бы, если честно, а хотелось бы if a = b<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=351274&view=findpost&p=3080736'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>ViktorXP &#064; <time class="tag-quote__quoted-time" datetime="2012-02-19T16:38:50+00:00">19.02.12, 16:38</time></span><div class='quote '>а чем TDelegate&lt;EventType&gt; будет отличатся от TList&lt;T&gt; (окромя того что у TDelegate меньше функционала);</div></div><br>
<br>
Инкапсуляция. Не из вредности же там меньше функционал, введены только те методы, которые соответствуют данному шаблону поведения. А остальные я бы сказал просто вредны. Объект, интересующийся событием должен уметь только подписаться и отписаться, все остальное строго говоря не его дело. <br>
<br>
Да и в принципе я большой противник использования классов типа TList в открытом интерфейсе - эти классы должны быть контейнерами на уровне внутренней логики, а на уровне внешней логики почти всегда должны быть инкапсулированы с предоставлением необходимого логике интерфейса доступа. Как пример - дочерние компоненты в VCL: тебе же дочерние компоненты не в виде TList предоставлены, а в виде индексированного свойства и ограниченного числа методов работы с реальным списком TList, сам же TList скрыт в дебрях внутренней кухни.]]></description>
        <author>--Ins--</author>
        <category>Все языки: Статьи, заготовки в FAQ</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3080736</guid>
        <pubDate>Sun, 19 Feb 2012 16:38:50 +0000</pubDate>
        <title>События с несколькими слушателями</title>
        <link>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3080736</link>
        <description><![CDATA[ViktorXP: а чем TDelegate&lt;EventType&gt; будет отличатся от TList&lt;T&gt; (окромя того что у TDelegate меньше функционала);]]></description>
        <author>ViktorXP</author>
        <category>Все языки: Статьи, заготовки в FAQ</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3080677</guid>
        <pubDate>Sun, 19 Feb 2012 13:56:34 +0000</pubDate>
        <title>События с несколькими слушателями</title>
        <link>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3080677</link>
        <description><![CDATA[ViktorXP: Довольно странный поиск. ;) <span class="tag-color tag-color-named" data-value="gray" style="color: gray">или так и задумывалось?</span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=351274&view=findpost&p=3079381'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>&#045;&#045;Ins&#045;&#045; &#064; <time class="tag-quote__quoted-time" datetime="2012-02-16T10:23:55+00:00">16.02.12, 10:23</time></span><div class='quote '><div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">function TDelegate&#60;EventType&#62;.FindHandler(Handler: EventType): Integer;</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;i: Integer;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Result := -1;</div><div class="code_line">&nbsp;&nbsp;for i := 0 to HandlersCount - 1 do</div><div class="code_line">&nbsp;&nbsp; &nbsp;if Compare(Handler, Handlers[i]) then begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;FHandlers.Delete(i);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;Break;</div><div class="code_line">&nbsp;&nbsp; &nbsp;end;</div><div class="code_line">end;</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script></div></div><br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=351274&view=findpost&p=3079381'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>&#045;&#045;Ins&#045;&#045; &#064; <time class="tag-quote__quoted-time" datetime="2012-02-16T10:23:55+00:00">16.02.12, 10:23</time></span><div class='quote '><div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">function TDelegate&#60;EventType&#62;.Compare(A, B: EventType): Boolean;</div><div class="code_line">var</div><div class="code_line">  m1, m2: PMethod;</div><div class="code_line">begin</div><div class="code_line">  // Грязно, знаю, ничего лучше не придумал, увы</div><div class="code_line">  m1 := PMethod(@A);</div><div class="code_line">  m2 := PMethod(@B);</div><div class="code_line">  Result := (m1^.Code = m2^.Code) and (m1^.Data = m2^.Data);</div><div class="code_line">end;</div></ol></div></div></div></div></div></div>А если так:<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">function TDelegate&#60;EventType&#62;.Compare(A, B: EventType): Boolean;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Result := CompareMem(@A, @B, SizeOf(EventType));</div><div class="code_line">end;</div></ol></div></div></div></div>]]></description>
        <author>ViktorXP</author>
        <category>Все языки: Статьи, заготовки в FAQ</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3079779</guid>
        <pubDate>Thu, 16 Feb 2012 20:24:57 +0000</pubDate>
        <title>События с несколькими слушателями</title>
        <link>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3079779</link>
        <description><![CDATA[--Ins--: <div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>Я думал добавить еще возможность отмены всплытия события, но это тут никуда не засунешь: если добавить параметр в обработчики, то все типы перекосятся.</div></div><br>
<br>
Как вариант - это Abort, но нужно для этого try..except(on EAbort - гасим исключение) в вызов обработчиков вставлять... Куда бы это засунуть чтобы не вставлять вручную....]]></description>
        <author>--Ins--</author>
        <category>Все языки: Статьи, заготовки в FAQ</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3079761</guid>
        <pubDate>Thu, 16 Feb 2012 18:53:15 +0000</pubDate>
        <title>События с несколькими слушателями</title>
        <link>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3079761</link>
        <description><![CDATA[Fr0sT: А я бы сделал подобие JavaScript-овского event bubbling - связанный список обработчиков, по которым поднимается событие. Тогда будет что-то вроде<br>
<br>
NotifyBubbler: EventBubbler&lt;TNotifyEvent&gt;;<br>
SomeObject.OnNotifyEvent := NotifyBubbler.Handler;<br>
NotifyBubbler.AddEventListener(SomeListenerObject.NotifyEventHandler); <br>
<br>
<span class="tag-color tag-color-named" data-value="gray" style="color: gray"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2012-02-16T18:56:24+00:00">16.02.12, 18:56</time></span></span><br>
P.S. В принципе, это почти то же самое, что и делегаты. Я думал добавить еще возможность отмены всплытия события, но это тут никуда не засунешь: если добавить параметр в обработчики, то все типы перекосятся.]]></description>
        <author>Fr0sT</author>
        <category>Все языки: Статьи, заготовки в FAQ</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3079381</guid>
        <pubDate>Thu, 16 Feb 2012 10:23:55 +0000</pubDate>
        <title>События с несколькими слушателями</title>
        <link>https://forum.sources.ru/index.php?showtopic=351274&amp;view=findpost&amp;p=3079381</link>
        <description><![CDATA[--Ins--: Для осуществления обратной связи в Delphi предусмотрен механизм событий - вызывающий код может обратиться к внешней среде для уведомления о действии, для запроса выполнения некоторых действий или для уточнения параметров. Все бы хорошо, но стандартный механизм событий в Delphi реализует отношение один-к-одному, а иногда удобно иметь один-ко-многим, т.е. чтобы объект смог уведомлять сразу нескольких подключенных к нему слушателей.<br>
Для решения этой задачи в Delphi я использую два различных механизма. Один предполагает реализацию классического паттерна Observer, когда класс регистрирует интерфейсы уведомления своих слушателей, а второй напоминает механизм Multicast-делегатов .NET. Первый способ удобно использовать в тех случаях, когда различных событий много и слушателю как правило нужны все или почти все они, а не лишь несколько. Второй - когда слушателя как правило интересуют лишь некоторые из событий.<br>
<br>
<strong class='tag-b'>1. Паттерн &quot;Observer&quot; (наблюдатель)</strong><br>
Для примера представим, что у нас есть объект, который должен уведомлять своих слушателей о событиях, допустим, Changing и Changed. Для того, чтобы реализовать уведомление нескольких слушателей об этих событий нужно:<br>
1. Объявить интерфейс слушателя<br>
2. Реализовать в объекте, возбуждающем события, механизм управления слушателями<br>
3. Реализовать в классах слушателях интерфейс слушателя<br>
4. Подключить слушатели к объекту<br>
Итак, объявим интерфейс<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">IMyObserver = interface</div><div class="code_line">&nbsp;&nbsp;[&#39;{93A613C8-5346-490F-B985-262AEB251355}&#39;]</div><div class="code_line">&nbsp;&nbsp;procedure ObjectChanging(AObject: TMyObject);</div><div class="code_line">&nbsp;&nbsp;procedure ObjectChanged(AObject: TMyObject);</div><div class="code_line">end;</div></ol></div></div></div></div><br>
Методы ObjectChanging/ObjectChanged - это те методы, которые должен реализовать слушатель и которые будет вызывать объект, инициирующий события (TMyObject).<br>
Для управления слушателями в классе TMyObject реализуем несколько методов:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">TMyObject = class</div><div class="code_line">private</div><div class="code_line">&nbsp;&nbsp;FObservers: TInterfaceList;</div><div class="code_line">protected</div><div class="code_line">&nbsp;&nbsp;// Методы, возбуждающие события</div><div class="code_line">&nbsp;&nbsp;procedure Changing;</div><div class="code_line">&nbsp;&nbsp;procedure Changed;</div><div class="code_line">public</div><div class="code_line">&nbsp;&nbsp;constructor Create;</div><div class="code_line">&nbsp;&nbsp;destructor Destroy; override;</div><div class="code_line">&nbsp;&nbsp;// Управление слушателями</div><div class="code_line">&nbsp;&nbsp;procedure RegisterObserver(const AObserver: IMyObserver);</div><div class="code_line">&nbsp;&nbsp;procedure UnRegisterObserver(const AObserver: IMyObserver);</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">implementation</div><div class="code_line">&nbsp;</div><div class="code_line">constructor TMyObject.Create;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;inherited;</div><div class="code_line">&nbsp;&nbsp;FObservers := TInterfaceList.Create;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">destructor TMyObject.Destroy;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;FObservers.Free;</div><div class="code_line">&nbsp;&nbsp;inherited;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">procedure TMyObject.Changing;</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;i: Integer;</div><div class="code_line">&nbsp;&nbsp;Obs: IMyObserver;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;// Вызываем обработчики события</div><div class="code_line">&nbsp;&nbsp;for i := 0 to FObservers.Count - 1 do begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;Obs := FObservers[i] as IMyObserver;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Obs.Changing(self);</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">procedure TMyObject.Changed;</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;i: Integer;</div><div class="code_line">&nbsp;&nbsp;Obs: IMyObserver;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;// Вызываем обработчики события</div><div class="code_line">&nbsp;&nbsp;for i := 0 to FObservers.Count - 1 do begin</div><div class="code_line">&nbsp;&nbsp; &nbsp;Obs := FObservers[i] as IMyObserver;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Obs.Changed(self);</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">procedure TMyObject.RegisterObserver(const AObserver: IMyObserver);</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;FObservers.Add(AObserver);</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">procedure TMyObject.UnRegisterObserver(const AObserver: IMyObserver);</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;FObservers.Remove(AObserver);</div><div class="code_line">end;</div></ol></div></div></div></div><br>
<br>
Ну и остается только реализовать слушателей и подключить их к нашему объекту. Слушателем можно сделать любой класс (ту же форму), реализовав в нем IMyObserver<br>
Простой пример класса-слушателя<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">TMyObserver = class(TInterfacedObject, IMyObserver)</div><div class="code_line">public</div><div class="code_line">&nbsp;&nbsp;procedure ObjectChanging(AObject: TMyObject);</div><div class="code_line">&nbsp;&nbsp;procedure ObjectChanged(AObject: TMyObject);</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">procedure TMyObserver.ObjectChanging(AObject: TMyObject);</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;ShowMessage(&#39;ObjectChanging&#39;);</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">procedure TMyObserver.ObjectChanged(AObject: TMyObject);</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;ShowMessage(&#39;ObjectChanged&#39;);</div><div class="code_line">end;</div></ol></div></div></div></div><br>
<br>
Ну и вот код регистрации слушателя:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;Obs: IMyObserver;</div><div class="code_line">&nbsp;&nbsp;Obj: TMyObject;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Obj := TMyObject.Create;</div><div class="code_line">&nbsp;&nbsp;Obs := TMyObserver.Create;</div><div class="code_line">&nbsp;&nbsp;Obj.RegisterObserver(Obs);</div></ol></div></div></div></div><br>
<br>
Теперь если возбудить событие, для каждого зарегистрированного слушателя будет вызван его интерфейсный метод<br>
<br>
<strong class='tag-b'>2. Делегат</strong><br>
Тем, кто знаком с .NET-ом известно что такое делегат. Для остальных поясним, что это специальный объект, который хранит в себе список методов-обработчиков событий (Handlers), позволяет управлять им (добавлять/удалять методы-обработчики) и вызывать эти методы при наступлении события. Реализация такого объекта в Delphi мне показалось интересной задачей, то, что в итоге получилось - продемонстрировано ниже.<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">type</div><div class="code_line">&nbsp;&nbsp;PMethod = ^TMethod;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;TEventHandler&#60;EventType&#62; = class(TObject)</div><div class="code_line">&nbsp;&nbsp;public</div><div class="code_line">&nbsp;&nbsp; &nbsp;Event: EventType;</div><div class="code_line">&nbsp;&nbsp; &nbsp;constructor Create(AEvent: EventType);</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;THandlerEnumarator&#60;EventType&#62; = class</div><div class="code_line">&nbsp;&nbsp;private</div><div class="code_line">&nbsp;&nbsp; &nbsp;FIndex: Integer;</div><div class="code_line">&nbsp;&nbsp; &nbsp;FList: TObjectList;</div><div class="code_line">&nbsp;&nbsp;public</div><div class="code_line">&nbsp;&nbsp; &nbsp;constructor Create(AList: TObjectList);</div><div class="code_line">&nbsp;&nbsp; &nbsp;function GetCurrent: EventType;</div><div class="code_line">&nbsp;&nbsp; &nbsp;function MoveNext: Boolean;</div><div class="code_line">&nbsp;&nbsp; &nbsp;property Current: EventType read GetCurrent;</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;// Базовый класс делегата</div><div class="code_line">&nbsp;&nbsp;TDelegate&#60;EventType&#62; = class(TObject)</div><div class="code_line">&nbsp;&nbsp;private</div><div class="code_line">&nbsp;&nbsp; &nbsp;FHandlers: TObjectList;</div><div class="code_line">&nbsp;&nbsp; &nbsp;function Compare(A, B: EventType): Boolean;</div><div class="code_line">&nbsp;&nbsp; &nbsp;function FindHandler(Handler: EventType): Integer;</div><div class="code_line">&nbsp;&nbsp; &nbsp;function GetHandler(Index: Integer): EventType;</div><div class="code_line">&nbsp;&nbsp; &nbsp;function GetHandlersCount: Integer;</div><div class="code_line">&nbsp;&nbsp;public</div><div class="code_line">&nbsp;&nbsp; &nbsp;constructor Create;</div><div class="code_line">&nbsp;&nbsp; &nbsp;destructor Destroy; override;</div><div class="code_line">&nbsp;&nbsp; &nbsp;procedure AddHandler(Handler: EventType);</div><div class="code_line">&nbsp;&nbsp; &nbsp;procedure RemoveHandler(Handler: EventType);</div><div class="code_line">&nbsp;&nbsp; &nbsp;function GetEnumerator: THandlerEnumarator&#60;EventType&#62;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;property HandlersCount: Integer read GetHandlersCount;</div><div class="code_line">&nbsp;&nbsp; &nbsp;property Handlers[Index: Integer]: EventType read GetHandler;</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;</div><div class="code_line">implementation</div><div class="code_line">&nbsp;</div><div class="code_line">{ TDelegate&#60;EventType&#62; }</div><div class="code_line">&nbsp;</div><div class="code_line">procedure TDelegate&#60;EventType&#62;.AddHandler(Handler: EventType);</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;FHandlers.Add(TEventHandler&#60;EventType&#62;.Create(Handler));</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">function TDelegate&#60;EventType&#62;.Compare(A, B: EventType): Boolean;</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;m1, m2: PMethod;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;// Грязно, знаю, ничего лучше не придумал, увы</div><div class="code_line">&nbsp;&nbsp;m1 := PMethod(@A);</div><div class="code_line">&nbsp;&nbsp;m2 := PMethod(@B);</div><div class="code_line">&nbsp;&nbsp;Result := (m1^.Code = m2^.Code) and (m1^.Data = m2^.Data);</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">constructor TDelegate&#60;EventType&#62;.Create;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;inherited;</div><div class="code_line">&nbsp;&nbsp;FHandlers := TObjectList.Create(True);</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">destructor TDelegate&#60;EventType&#62;.Destroy;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;FHandlers.Free;</div><div class="code_line">&nbsp;&nbsp;inherited;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">function TDelegate&#60;EventType&#62;.FindHandler(Handler: EventType): Integer;</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;i: Integer;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Result := -1;</div><div class="code_line">&nbsp;&nbsp;for i := 0 to HandlersCount - 1 do</div><div class="code_line">&nbsp;&nbsp; &nbsp;if Compare(Handler, Handlers[i]) then begin</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;FHandlers.Delete(i);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;Break;</div><div class="code_line">&nbsp;&nbsp; &nbsp;end;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">function TDelegate&#60;EventType&#62;.GetEnumerator: THandlerEnumarator&#60;EventType&#62;;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Result := THandlerEnumarator&#60;EventType&#62;.Create(FHandlers);</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">function TDelegate&#60;EventType&#62;.GetHandler(Index: Integer): EventType;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Result := TEventHandler&#60;EventType&#62;(FHandlers[Index]).Event;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">function TDelegate&#60;EventType&#62;.GetHandlersCount: Integer;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Result := FHandlers.Count;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">procedure TDelegate&#60;EventType&#62;.RemoveHandler(Handler: EventType);</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;Index: Integer;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Index := FindHandler(Handler);</div><div class="code_line">&nbsp;&nbsp;if Index &#62;= 0 then</div><div class="code_line">&nbsp;&nbsp; &nbsp;FHandlers.Delete(Index);</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">{ TEventHandler&#60;EventType&#62; }</div><div class="code_line">&nbsp;</div><div class="code_line">constructor TEventHandler&#60;EventType&#62;.Create(AEvent: EventType);</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;inherited Create;</div><div class="code_line">&nbsp;&nbsp;Event := AEvent;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">{ THandlerEnumarator&#60;EventType&#62; }</div><div class="code_line">&nbsp;</div><div class="code_line">constructor THandlerEnumarator&#60;EventType&#62;.Create(AList: TObjectList);</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;inherited Create;</div><div class="code_line">&nbsp;&nbsp;FIndex := -1;</div><div class="code_line">&nbsp;&nbsp;FList := AList;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">function THandlerEnumarator&#60;EventType&#62;.GetCurrent: EventType;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Result := TEventHandler&#60;EventType&#62;(FList[FIndex]).Event;</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">function THandlerEnumarator&#60;EventType&#62;.MoveNext: Boolean;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;Result := FIndex &#60; FList.Count - 1;</div><div class="code_line">&nbsp;&nbsp;if Result then</div><div class="code_line">&nbsp;&nbsp; &nbsp;Inc(FIndex);</div><div class="code_line">end;</div></ol></div></div></div></div><br>
<br>
Пользоваться теперь таким делегатом не сложнее чем обычными событиями. Допустим мы хотим реализовать событие с множеством слушателей типа TNotifyEvent. Объявим класс делегата:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">TNotifyEventDelegate = class(TDelegate&#60;TNotifyEvent&#62;);</div></ol></div></div></div></div><br>
Тип можно и не объявлять, а использовать вместо TNotifyEventDelegate подстановку TDelegate&lt;TNotifyEvent&gt;, но я предпочел объявить.<br>
Вместо привычного поля типа TNotifyEvent для события создадим в классе поле типа TNotifyEventDelegate:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp;TForm1 = class(TForm)</div><div class="code_line">&nbsp;&nbsp;private</div><div class="code_line">&nbsp;&nbsp; &nbsp;{ Private declarations }</div><div class="code_line">&nbsp;&nbsp; &nbsp;FClickEvent: TNotifyEventDelegate;</div><div class="code_line">&nbsp;&nbsp;public</div><div class="code_line">&nbsp;&nbsp; &nbsp;{ Public declarations }</div><div class="code_line">&nbsp;&nbsp; &nbsp;property ClickEvent: TNotifyEventDelegate read FClickEvent;</div><div class="code_line">&nbsp;&nbsp;end;</div></ol></div></div></div></div><br>
Для примера создадим пару обработчиков и добавим их в список делегата:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp;TForm1 = class(TForm)</div><div class="code_line">&nbsp;&nbsp; &nbsp;procedure FormCreate(Sender: TObject);</div><div class="code_line">&nbsp;&nbsp;private</div><div class="code_line">&nbsp;&nbsp; &nbsp;{ Private declarations }</div><div class="code_line">&nbsp;&nbsp; &nbsp;FClickEvent: TNotifyEventDelegate;</div><div class="code_line">&nbsp;&nbsp; &nbsp;procedure Handler1(Sender: TObject);</div><div class="code_line">&nbsp;&nbsp; &nbsp;procedure Handler2(Sender: TObject);</div><div class="code_line">&nbsp;&nbsp;public</div><div class="code_line">&nbsp;&nbsp; &nbsp;{ Public declarations }</div><div class="code_line">&nbsp;&nbsp; &nbsp;property ClickEvent: TNotifyEventDelegate read FClickEvent;</div><div class="code_line">&nbsp;&nbsp;end;</div><div class="code_line">&nbsp;</div><div class="code_line">implementation</div><div class="code_line">&nbsp;</div><div class="code_line">{$R *.dfm}</div><div class="code_line">&nbsp;</div><div class="code_line">procedure TForm2.FormCreate(Sender: TObject);</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;FClickEvent := TNotifyEventDelegate.Create;</div><div class="code_line">&nbsp;&nbsp;FClickEvent.AddHandler(Handler1);</div><div class="code_line">&nbsp;&nbsp;FClickEvent.AddHandler(Handler2);</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">procedure TForm2.Handler1(Sender: TObject);</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;ShowMessage(&#39;Handler 1&#39;);</div><div class="code_line">end;</div><div class="code_line">&nbsp;</div><div class="code_line">procedure TForm2.Handler2(Sender: TObject);</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;ShowMessage(&#39;Handler 2&#39;);</div><div class="code_line">end;</div></ol></div></div></div></div><br>
<br>
Ну и наконец - код, который инициирует событие - очень просто, если в обычных обработчиках мы бы написали<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">if Assigned(FOnClick) then FOnClick(Self)</div></ol></div></div></div></div><br>
То здесь нужно написать так:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">procedure TForm1.FormClick(Sender: TObject);</div><div class="code_line">var</div><div class="code_line">&nbsp;&nbsp;EventHandler: TNotifyEvent;</div><div class="code_line">begin</div><div class="code_line">&nbsp;&nbsp;for EventHandler in FClickEvent do EventHandler(Sender);</div><div class="code_line">end;</div></ol></div></div></div></div><br>
<br>
Вуаля&#33; При щелчке на форме появится два сообщения - это сработали два наших обработчика.<br>
<br>
На этом все :) Комментарии/пожелания приветствуются]]></description>
        <author>--Ins--</author>
        <category>Все языки: Статьи, заготовки в FAQ</category>
      </item>
	
      </channel>
      </rss>
	