<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Go!Verla Flex Blog &#187; Action Script</title>
	<atom:link href="http://tearaway-tea.com/blog/category/action-script/feed/ru/" rel="self" type="application/rss+xml" />
	<link>http://tearaway-tea.com/blog</link>
	<description>от Евгения Тютюнника</description>
	<lastBuildDate>Mon, 31 Aug 2009 04:21:11 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>ru</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Инвалидация свойств невизуальных объектов</title>
		<link>http://tearaway-tea.com/blog/2009/04/%d0%b8%d0%bd%d0%b2%d0%b0%d0%bb%d0%b8%d0%b4%d0%b0%d1%86%d0%b8%d1%8f-%d1%81%d0%b2%d0%be%d0%b9%d1%81%d1%82%d0%b2-%d0%bd%d0%b5%d0%b2%d0%b8%d0%b7%d1%83%d0%b0%d0%bb%d1%8c%d0%bd%d1%8b%d1%85-%d0%be%d0%b1/ru/</link>
		<comments>http://tearaway-tea.com/blog/2009/04/%d0%b8%d0%bd%d0%b2%d0%b0%d0%bb%d0%b8%d0%b4%d0%b0%d1%86%d0%b8%d1%8f-%d1%81%d0%b2%d0%be%d0%b9%d1%81%d1%82%d0%b2-%d0%bd%d0%b5%d0%b2%d0%b8%d0%b7%d1%83%d0%b0%d0%bb%d1%8c%d0%bd%d1%8b%d1%85-%d0%be%d0%b1/ru/#comments</comments>
		<pubDate>Thu, 16 Apr 2009 14:58:47 +0000</pubDate>
		<dc:creator>tearaway_Tea</dc:creator>
				<category><![CDATA[Action Script]]></category>
		<category><![CDATA[Flex]]></category>

		<guid isPermaLink="false">http://tearaway-tea.com/blog/?p=311</guid>
		<description><![CDATA[Наверно, следовало бы сначала описать своё понимание паттерна «Инвалидация чего-либо» во Flex. Может быть напишу статью о полезности такого подхода в разработке визуальных компонентов. В общем, возможно, вы часто используете пару методов invalidateProperties() / commitProperties() для отложеного выполнения логики set методов свойств ваших компонентов. Эта пара определена в базовом для всех Flex контролов классе UIComponent.
Краткий [...]]]></description>
			<content:encoded><![CDATA[<p>Наверно, следовало бы сначала описать своё понимание паттерна «Инвалидация чего-либо» во Flex. Может быть напишу статью о полезности такого подхода в разработке визуальных компонентов. В общем, возможно, вы часто используете пару методов <em>invalidateProperties()</em> / <em>commitProperties()</em> для отложеного выполнения логики set методов свойств ваших компонентов. Эта пара определена в базовом для всех Flex контролов классе UIComponent.</p>
<p>Краткий смысл паттерна в том, что мы ожидаем присваивание значений набору свойств компонента в течение одного кадра Flash Player-а, а последующюю логику обработки этих значений переносим на следующий кадр. Это может повысить производительность приложения, а так же навести порядок в обработке значений связанных между собой свойств компонента.</p>
<p>Полагаю, что инвалидация свойств компонентов во Flex практикуется потому, что большинство компонентов инстанциируется посредством MXML и порядок присваивания свойств спрогнозировать невозможно.</p>
<p>Но, на практике, возникаются ситуации, когда подобный механизм нужен и в невизуальных объектах, например элементах модели бизнес-логики, которые приходят от сервера.</p>
<p><span id="more-311"></span><br />
Я подготовил простой <a title="Properties Invalidation" href="http://tearaway-tea.googlecode.com/svn/trunk/propertiesInvalidation/index.html">пример</a>, который демонстрирует суть задачи.</p>
<p>Допустим у нас есть класс модели <a title="OpportunityDTO" href="http://code.google.com/p/tearaway-tea/source/browse/trunk/propertiesInvalidation/src/com/tearaway_tea/model/OpportunityDTO.as">OpportunityDTO</a>, экземпляры которого получаются от сервера и создаются AMF десериализатором Flash Player-а, который нам не подконтролен. В нём есть два свойства <em>date</em>, <em>children</em>, в момент присваивания значений которых, нам нужна дополнительная обработка. Эта обработка должна выполняться только тогда, когда оба свойства получили свои значения. Типичный случай для паттерна инвалидации свойств.</p>
<pre><code>package com.tearaway_tea.model
{
	import flash.events.EventDispatcher;

	import mx.collections.ArrayCollection;

	import org.goverla.interfaces.IPropertiesInvalidable;
	import org.goverla.managers.PropertiesInvalidationManager;

	public class OpportunityDTO extends EventDispatcher implements IPropertiesInvalidable
	{
		public function get date() : Date
		{
			return _date;
		}

		public function set date(value : Date) : void
		{
			_date = value;
			_dateChanged = true;
			invalidateProperties();
		}

		public function get children() : ArrayCollection
		{
			return _children;
		}

		public function set children(value : ArrayCollection) : void
		{
			_children = value;
			_childrenChanged = true;
			invalidateProperties();
		}

		public function invalidateProperties() : void
		{
			PropertiesInvalidationManager.instance.invalidateProperties(this);
		}

		public function commitProperties() : void
		{
			if (_dateChanged &amp;&amp; _childrenChanged)
			{
				_dateChanged = false;
				_childrenChanged = false;

				for each (var item : ItemDTO in children)
				{
					item.name += "/" + date.toString();
				}
			}
		}

		private var _date : Date;

		private var _dateChanged : Boolean;

		private var _children : ArrayCollection;

		private var _childrenChanged : Boolean;
	}
}</code></pre>
<p>Для решения этой задачи я предлагаю использовать синглтон <a title="PropertiesInvalidationManager" href="http://code.google.com/p/goverla/source/browse/trunk/goverla/src/org/goverla/managers/PropertiesInvalidationManager.as">PropertiesInvalidationManager</a>, который работает по образу и подобию флексовского LayoutManager-а.</p>
<pre><code>package org.goverla.managers
{
	import mx.rpc.AsyncDispatcher;

	import org.goverla.interfaces.IPropertiesInvalidable;

	public class PropertiesInvalidationManager
	{
		public static function get instance() : PropertiesInvalidationManager
		{
			if (_instance == null)
			{
				_instance = new PropertiesInvalidationManager();
			}
			return _instance;
		}

		private static var _instance : PropertiesInvalidationManager;

		public function invalidateProperties(target : IPropertiesInvalidable) : void
		{
			if (_targets.indexOf(target) &lt; 0)
			{
				_targets.push(target);

				if (_dispatcher == null)
				{
					_dispatcher =
						new AsyncDispatcher(commitProperties, [], 0);
				}
			}
		}

		public function commitProperties() : void
		{
			for each (var target : IPropertiesInvalidable in _targets)
			{
				target.commitProperties();
			}
			_targets = [];
			_dispatcher = null;
		}

		private var _targets : Array = [];

		private var _dispatcher : AsyncDispatcher;

	}
}</code></pre>
<p>Суть очевидна. Менеджер получает ссылку на объект, который нуждается в инвалидации свойств, ставит его в очередь и на следующем кадре вызывает у него <em>commitProperties()</em>. Для откладывания выполнения используется флексовский AsyncDispatcher, который основан на Timer.</p>
<p>Для удобства использования, можна создать какой-то базовый класс, который будет имплементировать интерфейс IPropertiesInvalidable.</p>
]]></content:encoded>
			<wfw:commentRss>http://tearaway-tea.com/blog/2009/04/%d0%b8%d0%bd%d0%b2%d0%b0%d0%bb%d0%b8%d0%b4%d0%b0%d1%86%d0%b8%d1%8f-%d1%81%d0%b2%d0%be%d0%b9%d1%81%d1%82%d0%b2-%d0%bd%d0%b5%d0%b2%d0%b8%d0%b7%d1%83%d0%b0%d0%bb%d1%8c%d0%bd%d1%8b%d1%85-%d0%be%d0%b1/ru/feed/ru/</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>Пример использования «слабых» ссылок</title>
		<link>http://tearaway-tea.com/blog/2009/02/%d0%bf%d1%80%d0%b8%d0%bc%d0%b5%d1%80-%d0%b8%d1%81%d0%bf%d0%be%d0%bb%d1%8c%d0%b7%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f-%c2%ab%d1%81%d0%bb%d0%b0%d0%b1%d1%8b%d1%85%c2%bb-%d1%81%d1%81%d1%8b%d0%bb%d0%be/ru/</link>
		<comments>http://tearaway-tea.com/blog/2009/02/%d0%bf%d1%80%d0%b8%d0%bc%d0%b5%d1%80-%d0%b8%d1%81%d0%bf%d0%be%d0%bb%d1%8c%d0%b7%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f-%c2%ab%d1%81%d0%bb%d0%b0%d0%b1%d1%8b%d1%85%c2%bb-%d1%81%d1%81%d1%8b%d0%bb%d0%be/ru/#comments</comments>
		<pubDate>Wed, 25 Feb 2009 18:39:28 +0000</pubDate>
		<dc:creator>tearaway_Tea</dc:creator>
				<category><![CDATA[Action Script]]></category>

		<guid isPermaLink="false">http://tearaway-tea.com/blog/?p=160</guid>
		<description><![CDATA[Тема «слабых» ссылок при установлении функций-слушателей (англ. listener) для событий в Action Script уже подымалась не раз несколько лет подряд. Я, например, стараюсь следить за всеми новостями от Adobe, давно знавший о их существовании, тем не менее, понял их суть совсем недавно, только после использования профайлера в Flex Builder.
Известный товарищ gskinner ещё в далёком 2006 [...]]]></description>
			<content:encoded><![CDATA[<p>Тема «слабых» ссылок при установлении функций-слушателей (англ. listener) для событий в <em>Action Script</em> уже подымалась не раз несколько лет подряд. Я, например, стараюсь следить за всеми новостями от Adobe, давно знавший о их существовании, тем не менее, понял их суть совсем недавно, только после использования профайлера в <em>Flex Builder</em>.</p>
<p>Известный товарищ <em>gskinner</em> ещё в далёком 2006 году <a title="AS3: Weakly Referenced Listeners" href="http://gskinner.com/blog/archives/2006/07/as3_weakly_refe.html">удивлялся</a> почему все слушатели по умолчанию не подключаются в режиме <em>weak reference</em>, а некоторые ребята на Хабре, в комментах к <a title="Контексты функций в Action Script" href="http://habrahabr.ru/blogs/flex/52458/">статье про контексты функций</a>, вообще считают, что «слабые» ссылки от нечистого и все операции по удалению онных нужно производить исключительно вручную!</p>
<p>Вместо пересказывания справочной информации я приведу пример, в котором я вижу исключительную полезность использования «слабых» ссылок.</p>
<p><span id="more-160"></span></p>
<pre><code>public class GuestbookEntry
{
	public function get comments() : ArrayCollection
	{
		return _comments;
	}

	public function set comments(value : ArrayCollection) : void
	{
		if (_comments != null)
		{
			_comments.removeEventListener(CollectionEvent.COLLECTION_CHANGE,
				onCommentsChange);
		}

		_comments = value;

		if (value != null)
		{
			value.addEventListener(CollectionEvent.COLLECTION_CHANGE,
				onCommentsChange, false, 0, true);
		}
	}

	protected function onCommentsChange(event : CollectionEvent) : void
	{
		switch (event.kind)
		{
			case CollectionEventKind.ADD :
				CommentEntry(event.items[0]).guestbookEntry = this;
				break;
		}
	}

	private var _comments : ArrayCollection;
}</code></pre>
<p>Представим, у нас есть гостевая книга, и тип её записи GuestbookEntry представленый выше. У этого типа есть коллекция комментариев. Пусть комментарий описывается типом CommentEntry. Где-то есть форма для добавления новых комментов, у нас есть требование архитектуры проекта, что-бы каждый коммент имел ссылку на запись книги посредством свойства <em>guestbookEntry</em>.</p>
<p>Экземпляры GuestbookEntry скорее всего будут получены от сервера, неважно. В сетере свойства comments я подписываюсь на событие изменения коллекции, что-бы контроллировать  момент добавления нового коммента. Как видим, ссылка на функцию <em>onCommentsChange</em> передаётся в коллекцию как «слабая» (последний аргумент метода <em>addEventListener</em>).</p>
<p>Во время профайлинга приложения с подобным кодом, до использования в нём «слабой» ссылки,  в памяти оставались все когда-либо созданые экземпляры класса GuestbookEntry. Инспектор «висячих» (англ. loitering) объектов показывал две связи между экземплярами GuestbookEntry и CommentEntry: одна посредством свойства <em>guestbookEntry</em>, другая, косвенная, посредством функции <em>onCommentsChange</em> (её экземпляр хранился в коллекции комментов, а <em>savedThis </em>(по-сути, <a title="Контексты функций в Action Script" href="http://tearaway-tea.com/blog/2009/02/контексты-функций-в-action-script/">контекст функции</a>) у функции ссылался на запись гостевой).</p>
<p>На сколько я понял, сборщик мусора в <em>Flash Player</em> автоматически очищает память от связаных между собой объектов только через прямые ссылки (циклические вчастности), если же есть косвенные (все подписки на события) связи, он — бессилен. Сдесь нам и помагают «слабые» ссылки. Никакого риска использования их нет, так как это, зачастую, последние оставшиеся ссылки между объектами, готовыми к удалению.</p>
<p>Внимательный читатель, который любит <em>Фаулера</em>, заметит и спросит о том, что нам мешает удалять в ручную такие ссылки? А я отвечу — ничего не мешает, но подобные решения будут громоздкими и некрасивыми. В данном случае, мне нужно было бы реализовать в типе GuestbookEntry, что-то вроде метода <em>dispose()</em>:</p>
<pre><code>public function dispose() : void
{
	comments = null;
}</code></pre>
<p>И вызывать этот метод во всех местах потенциального «прощания» с экземплярами записей гостевой книги. Скучно, старомодно и не практично.</p>
<p><strong>UPD:</strong> Поразмыслив с коллегами по работе, выяснилось пару аспектов когда «слабые» ссылки могут подложить вам свинью. Например, если у вас остался «неприкаянный» объект, на который ссылаются «слабой» ссылкой, до момента уничтожения его сборщиком мусора, он будет получать события (ведь ссылка есть) и возможно, обработка этих событий будет вами не запланирована, так как вы, уже, мысленно «распрощались» с объектом. Что-бы избежать подобных ситуаций, конечно-же, нужно удалять слушателей вручную.</p>
<p>В данном примере криминала нет, так как записи гостевой книги с их комментариями удаляются комплексно, то изменение коллекции комментов, после удаления прямых ссылок на экземпляры GuestbookEntry и до уничтожения их сборщиком — невозможно.</p>
]]></content:encoded>
			<wfw:commentRss>http://tearaway-tea.com/blog/2009/02/%d0%bf%d1%80%d0%b8%d0%bc%d0%b5%d1%80-%d0%b8%d1%81%d0%bf%d0%be%d0%bb%d1%8c%d0%b7%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f-%c2%ab%d1%81%d0%bb%d0%b0%d0%b1%d1%8b%d1%85%c2%bb-%d1%81%d1%81%d1%8b%d0%bb%d0%be/ru/feed/ru/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Контексты функций в Action Script</title>
		<link>http://tearaway-tea.com/blog/2009/02/%d0%ba%d0%be%d0%bd%d1%82%d0%b5%d0%ba%d1%81%d1%82%d1%8b-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b9-%d0%b2-action-script/ru/</link>
		<comments>http://tearaway-tea.com/blog/2009/02/%d0%ba%d0%be%d0%bd%d1%82%d0%b5%d0%ba%d1%81%d1%82%d1%8b-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b9-%d0%b2-action-script/ru/#comments</comments>
		<pubDate>Fri, 20 Feb 2009 14:13:04 +0000</pubDate>
		<dc:creator>tearaway_Tea</dc:creator>
				<category><![CDATA[Action Script]]></category>

		<guid isPermaLink="false">http://tearaway-tea.com/blog/?p=130</guid>
		<description><![CDATA[Я люблю использовать анонимные функции, передавать функции по ссылке, объявлять функции прямо в теле другой функции и т.п. Это удобно и практично, но с этими механизмами могут возникнуть некоторые проблемы. Начиная с версии 9 Flash Player сохраняет в this функции её родителя. Звучит просто, но все ли понимают, что это значит и как тяжело было [...]]]></description>
			<content:encoded><![CDATA[<p>Я люблю использовать анонимные функции, передавать функции по ссылке, объявлять функции прямо в теле другой функции и т.п. Это удобно и практично, но с этими механизмами могут возникнуть некоторые проблемы. Начиная с версии 9 <em>Flash Player</em> сохраняет в <em>this</em> функции её родителя. Звучит просто, но все ли понимают, что это значит и как тяжело было раньше без этого?</p>
<p>Например, теперь можно описать такую функцию:</p>
<pre><code>public class TestClass
{
	var property : Number;

	function updateValue(value : Number) : void
	{
		TestClass(this).property = value;
	}
}</code></pre>
<p>и передавать её куда угодно:</p>
<pre><code>var func : Function = new TestClass().updateValue;
func(555);</code></pre>
<p>и быть уверенным, где-бы её не вызвали в <em>this</em> будет экземпляр класса TestClass. Но я не об этом, есть более любопытные действия, которые можно производить над функциями в <em>Action Script</em>, их мы их рассмотрим.<br />
<span id="more-130"></span></p>
<h3>Асинхронные вызовы</h3>
<p>Скорее всего вы сталкивались с задачей вызова удаленного метода на сервере и обработки результата этого вызова. Допустим у нас есть класс сервиса <a title="Подробнее о паттерне" href="http://tearaway-tea.com/blog/2009/02/оптимальный-паттерн-для-работы-с-remoteobject/">ServerService</a>, который принимает в конструктор ссылку на функцию, которая должна обработать ответ и мы выполняем типичную задачу обновления свойства исходного объекта:</p>
<pre><code>class Example
{
	function updateItem(item : SomeObject) : void
	{
		_tempObject = item;
		new ServerService(onGetResult).getResult(item.startValue);
	}

	function onGetResult(result : Object) : void
	{
		_tempObject.endValue = result;
	}

	private var _tempObject : SomeObject;
}</code></pre>
<p>Всё написано верно, но зачем так сложно? Давайте упростим подобную ерунду, «умным» кодом:</p>
<pre><code>function updateItem(item : SomeObject) : void
{
	new ServerService(onGetResult).getResult(item.startValue);

	function onGetResult(result : Object) : void
	{
		item.endValue = result;
	}
}</code></pre>
<p>В данном случае функция <em>onGetResult</em> имеет доступ ко всем переменным функции <em>updateItem</em> и к её аргументу <em>item</em> в частности. Такой прием во многих случаях может сократить объем кода и убрать негативный оттенок асинхронности. Кстати, в <em>this</em> функции <em>onGetResult</em> будет уже не экземпляр Example, а просто <em>global</em>.</p>
<h3>Множественные асинхронные вызовы</h3>
<p>Ещё интереснее ситуации когда нужно сделать несколько асинхронных запросов в цикле, а затем обработать каждый ответ соответственно, например:</p>
<pre><code>function updateItems(items : ArrayCollection) : void
{
	for each (var item : SomeObject in items)
	{
		new ServerService(onGetResult).getResult(item.startValue);
	}

	function onGetResult(result : Object) : void
	{
		item.endValue = result;
	}
}</code></pre>
<p>Данным кодом мы не достигнем желаемого результата. В тот момент когда сервер вернёт нам ответы, переменная <em>item</em> будет ссылаться на последний элемент коллекции <em>items</em> и все данные присвоятся только ему, слишком много чести! В таких ситуациях не помогает ни сохраняемый контекст функции ни область видимости переменных родителя, тут нужно что-то другое.</p>
<p>Зачастую можно воспользоваться так называемым Loader-ом:</p>
<pre><code>function updateItems(items : ArrayCollection) : void
{
	for each (var item : SomeObject in items)
	{
		new ValueLoader(item);
	}
}

class ValueLoader
{
	public function ValueLoader(item : SomeObject)
	{
		new ServerService(onGetResult).getResult(item.startValue);

		function onGetResult(result : Object) : void
		{
			item.endValue = result;
		}
	}
}</code></pre>
<p>Так как контекста функции недостаточно что-бы сохранить <em>item</em> для обновления его после ответа сервера, мы создаем над функцией обёртку — класс, которые способен запомнить в контексте всё что нужно. Так как конструктор класса всё та же функция, аргумент <em>item</em> без проблем будет доступен в функции <em>onGetResult</em>.</p>
<h3>Стандартизированый объект ContextFunction</h3>
<p>В конце концов, если вы нежелаете плодить массу всевозможных Loader-ов, можно ввести универсальный тип — паттерн для многократного использования:</p>
<pre><code>class ContextFunction
{
	public function ContextFunction(targetFunction : Function, ... args)
	{
		_contextArgumnets = args;
		_targetFunction = targetFunction;
	}

	public function func(... args) : void
	{
		var targetArguments : Array = args.concat(_contextArgumnets);
		_targetFunction.apply(this, targetArguments);
	}

	private var _contextArgumnets : Array;

	private var _targetFunction : Function;
}</code></pre>
<p>Суть решения в том, что экземпляр ContextFunction определяется ссылкой на функцию с конкретной логикой и набором неопределённых аргументов, которые получит функция, когда её кто-то вызовет. Так же, к этим аргументам добавятся ещё что-то, по желанию вызывающей сущности. Рассмотрим пример для прояснения:</p>
<pre><code>function updateItems(items : ArrayCollection) : void
{
	for each (var item : SomeObject in items)
	{
		new ServerService(new ContextFunction(onGetResult, item).func).
			getResult(item.startValue);
	}
}

function onGetResult(result : Object, item : SomeObject) : void
{
	item.endValue = result;
}</code></pre>
<p>Это по-сути то же решение, что и с Loader-ом, только более универсальное. Экземпляр ContextFunction сохраняет <em>onGetResult</em>, которая получит ответ от сервера, а также ссылку на <em>item</em> для которого запрашивалось серверное значение. То-есть, мы, отказываясь от контекста функции вообще, используем экземпляр вспомагательного класса, для сохранения нужных значений.</p>
<p>В заключение, могу вас уверить, что все эти трюки используются мной на практике очень часто и эффективно. Это не высосанные из пальца проблемы.</p>
]]></content:encoded>
			<wfw:commentRss>http://tearaway-tea.com/blog/2009/02/%d0%ba%d0%be%d0%bd%d1%82%d0%b5%d0%ba%d1%81%d1%82%d1%8b-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b9-%d0%b2-action-script/ru/feed/ru/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Оптимальный паттерн для работы с RemoteObject</title>
		<link>http://tearaway-tea.com/blog/2009/02/%d0%be%d0%bf%d1%82%d0%b8%d0%bc%d0%b0%d0%bb%d1%8c%d0%bd%d1%8b%d0%b9-%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-%d0%b4%d0%bb%d1%8f-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d1%8b-%d1%81-remoteobject/ru/</link>
		<comments>http://tearaway-tea.com/blog/2009/02/%d0%be%d0%bf%d1%82%d0%b8%d0%bc%d0%b0%d0%bb%d1%8c%d0%bd%d1%8b%d0%b9-%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-%d0%b4%d0%bb%d1%8f-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d1%8b-%d1%81-remoteobject/ru/#comments</comments>
		<pubDate>Fri, 20 Feb 2009 14:03:45 +0000</pubDate>
		<dc:creator>tearaway_Tea</dc:creator>
				<category><![CDATA[Action Script]]></category>
		<category><![CDATA[Flex]]></category>

		<guid isPermaLink="false">http://tearaway-tea.com/blog/?p=139</guid>
		<description><![CDATA[В продолжение темы советов новичкам, поведаю о самом удобном способе инкапсуляции вызовов серверных методов. Назовём этот паттерн ServiceBase, по-сути это базовый класс, от которого должны наследоваться ваши сервисы (наборы методов, соответствующие серверным):

class ServiceBase
{
	public function ServiceBase(destination : String,
		resultHandler : Function = null, faultHandler : Function = null)
	{
		_resultHandler = resultHandler;
		_faultHandler = faultHandler;

		_remoteObject = new RemoteObject(destination);
	}

	protected function call(name [...]]]></description>
			<content:encoded><![CDATA[<p>В продолжение темы <a title="Советы новичкам" href="http://tearaway-tea.com/blog/2008/12/советы-новичкам/">советов новичкам</a>, поведаю о самом удобном способе инкапсуляции вызовов серверных методов. Назовём этот паттерн ServiceBase, по-сути это базовый класс, от которого должны наследоваться ваши сервисы (наборы методов, соответствующие серверным):<br />
<span id="more-139"></span></p>
<pre><code>class ServiceBase
{
	public function ServiceBase(destination : String,
		resultHandler : Function = null, faultHandler : Function = null)
	{
		_resultHandler = resultHandler;
		_faultHandler = faultHandler;

		_remoteObject = new RemoteObject(destination);
	}

	protected function call(name : String, args : Array) : void
	{
		CursorManager.setBusyCursor();

		var operation : AbstractOperation = _remoteObject.getOperation(name);
		operation.addEventListener(ResultEvent.RESULT, onResult);
		operation.addEventListener(FaultEvent.FAULT, onFault);
		operation.send.apply(operation, args);
	}

	protected function onResult(event : ResultEvent) : void
	{
		CursorManager.removeBusyCursor();

		if (_resultHandler != null)
		{
			_resultHandler(event.result);
		}
	}

	protected function onFault(event : FaultEvent) : void
	{
		CursorManager.removeBusyCursor();

		if (_faultHandler != null)
		{
			_faultHandler(event.fault);
		}
	}

	private var _resultHandler : Function;

	private var _faultHandler : Function;

	private var _remoteObject : RemoteObject;
}</code></pre>
<p>Я иногда наблюдал подобные подходы в коде западных коллег, но схема была несколько иная, менее удобная. Навскидку, данный класс нам ни о чём не говорит, но в паре с таким классом, должно всё проясниться:</p>
<pre><code>class GuestbookService extends ServiceBase
{
	public function GuestbookService(resultHandler : Function = null,
		faultHandler : Function = null)
	{
		super("GuestbookAction", resultHandler, faultHandler);
	}

	public function getGuestbookEntries() : void
	{
		call("getGuestbookEntries", arguments);
	}

	public function getEntryById(id : Number) : void
	{
		call("getEntryById", arguments);
	}

	public function updateEntry(id : Number, text : String) : void
	{
		call("updateEntry", arguments);
	}
}</code></pre>
<p>Этот класс я называю сервисом по работе с гостевой книгой. В нём есть все те же методы, что и в серверном классе GuestbookAction (гейтвее или сервлете, в зависимости от платформы). В конструктор можно передать ссылки на функции, которые получат ответ от сервера или информацию о ошибке. Пример использования:</p>
<pre><code>new GuestbookService().updateEntry(5, "Nice solution!");</code></pre>
<p>или</p>
<pre><code>new GuestbookService(onGetEntryById).getEntryById(6);

function onGetEntryById(result : GuestbookEntry) : void
{
	_list.addItem(result);
}</code></pre>
<p>Основной принцип заключается в том, что мы не сохраняем ссылку на экземпляр класса GuestbookService, после того, как он отработает запрос — он нам не нужен. Этот факт можно использовать при множественном вызове серверного метода, каждный раз создавая новый экземпляр сервиса.</p>
<p>Мне этот подход нравится больше чем низкоуровневое конструирование запроса на основе RemoteObject своей прозрачностью и простотой. Так же, подобные наследники можно и следует генерировать автоматически на основе серверных классов. Тогда, вы получаете полный контроль над соответствием названий серверных методов, а так же их сигнатур. Компилятор просто не соберёт ваш проект, если вы не исправите ошибку.</p>
<p>Так же, подобное решение может вам помочь при юнит-тестировании, подменяя базовый класс чем-то вроде MockServiceBase.</p>
]]></content:encoded>
			<wfw:commentRss>http://tearaway-tea.com/blog/2009/02/%d0%be%d0%bf%d1%82%d0%b8%d0%bc%d0%b0%d0%bb%d1%8c%d0%bd%d1%8b%d0%b9-%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-%d0%b4%d0%bb%d1%8f-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d1%8b-%d1%81-remoteobject/ru/feed/ru/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
