Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > Rembrant

Оценить эту запись

ООП ради ООП ч. 2. Мучаем robotlegs

Запись от Rembrant размещена 21.07.2014 в 19:22

Некоторое время назад я пытался создать as3-приложение на основе библиотеки pureMVC, результат этих мучений можно лицезреть здесь. Среди прочего, было отмечено крайнее неудобство pureMVC как таковой, что сподвигло меня покопаться для сравнения ещё в одном MVC-фреймворке, robotlegs, знание которого также требуется довольно часто.

Итак, представляю на суд публики ту же самую галлерею, но уже на основании robotlegs. На оф. сайте доступны 2 версии - 1.5.2 и 2.2.1, соответственно у меня получилось 2 проекта, потому что реализация на этих двух версиях НУ ОЧЕНЬ отличается. Дальше попытаюсь разжевать (для себя в том числе) код проекта для версии 2.2.1 как самой прогрессивной, ну и в конце упомяну про отличия.

Часть 1. Программка на robotlegs 2.2.1
Дерево проекта:



Как и все каноничные MVC-фреймворки, robotlegs имеет модели, команды и медиаторы. Плюс - контекст. Контекст - это класс самонастройки, инициализирующий зависимости между компонентами программы. Он инициализируется в Main одной строкой:
Код AS3:
 _context = new GalleryContext(this);
GalleryContext - мой класс, который конфигурирует библиотечный Context следующим образом.

GalleryContext.as:
Код AS3:
 package app  
{
	import flash.display.DisplayObjectContainer;
	import robotlegs.bender.bundles.mvcs.MVCSBundle;
	import robotlegs.bender.extensions.contextView.ContextView;
	import robotlegs.bender.framework.api.IContext;
	import robotlegs.bender.framework.impl.Context;
 
	public class GalleryContext
	{
		public function GalleryContext(view:DisplayObjectContainer) 
		{
			context = new Context()
				.install(MVCSBundle)
				.configure(GalleryConfig)
				.configure(new ContextView(view));
		}
 
		private var context:IContext;
	}
}
Здесь важны 2 момента:
- конфигурируется ContextView, куда передаётся наш view, то есть Main;
- конфигурируется пользовательский GalleryConfig, в котором описаны все команды, медиаторы и модели.

GalleryConfig.as:
Код AS3:
 package app 
{
	import app.controller.ClosePreviewCommand;
	import app.controller.CreateMainPanelCommand;
	import app.controller.ImageClickCommand;
	import app.controller.LoadAllCommand;
	import app.events.GalleryEvent;
	import app.model.ImageModel;
	import app.view.MainPanelTile;
	import app.view.MainPanelTileMediator;
	import app.view.Preview;
	import app.view.PreviewMediator;
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	import robotlegs.bender.extensions.contextView.ContextView;
	import robotlegs.bender.extensions.eventCommandMap.api.IEventCommandMap;
	import robotlegs.bender.extensions.mediatorMap.api.IMediatorMap;
	import robotlegs.bender.framework.api.IConfig;
	import robotlegs.bender.framework.api.IContext;
	import robotlegs.bender.framework.api.IInjector;
 
	public class GalleryConfig implements IConfig
	{
 
		public function GalleryConfig() { }
 
		//--------------------------------------------------------------------------
		//
		// PUBLIC SECTION 
		//
		//--------------------------------------------------------------------------
		[Inject]
		public var injector:IInjector;
 
		[Inject]
		public var mediatorMap:IMediatorMap;
 
		[Inject]
		public var commandMap:IEventCommandMap;
 
		[Inject]
		public var contextView:ContextView;
 
		[Inject]
		public var context:IContext;
 
		[Inject]
		public var dispatcher:IEventDispatcher;
 
		public function configure():void
		{
			injector.map(ImageModel).asSingleton();
 
			commandMap.map(Event.INIT).toCommand(LoadAllCommand);
			commandMap.map(GalleryEvent.LOAD_COMPLETE).toCommand(CreateMainPanelCommand);
			commandMap.map(GalleryEvent.IMAGE_CLICK).toCommand(ImageClickCommand);
			commandMap.map(GalleryEvent.CLOSE_PREVIEW).toCommand(ClosePreviewCommand);
 
			mediatorMap.map(MainPanelTile).toMediator(MainPanelTileMediator);
			mediatorMap.map(Preview).toMediator(PreviewMediator);
 
			context.afterInitializing(init);
		}
 
		//--------------------------------------------------------------------------
		//
		// PRIVATE SECTION 
		//
		//--------------------------------------------------------------------------
		private function init():void
		{
			dispatcher.dispatchEvent(new Event(Event.INIT));
		}
	}
}
В этом классе впервые видим магическое слово [Inject] - ранее неведомая для меня флешовая директива, позволяющая достучаться практически до любого элемента модели. Скажем, если классу нужно продиспатчить событие, достаточно заинжектить глобальный диспатчер:
Код AS3:
 		[Inject]
		public var dispatcher:IEventDispatcher;
После этого происходит магия, и переменная dispatcher становится доступной для использования во всём классе.

Чтобы наши команды, модели и медиаторы работали в проекте, они должны быть "замаплены" следующими товарищами:
Код AS3:
 		[Inject]
		public var injector:IInjector;
 
		[Inject]
		public var mediatorMap:IMediatorMap;
 
		[Inject]
		public var commandMap:IEventCommandMap;
Проще всего замапить модель (она у нас одна):
Код AS3:
 injector.map(ImageModel).asSingleton();
Команды обычно вызываются событиями, соответственно они связываются в пары:
Код AS3:
 			commandMap.map(Event.INIT).toCommand(LoadAllCommand);
			commandMap.map(GalleryEvent.LOAD_COMPLETE).toCommand(CreateMainPanelCommand);
			commandMap.map(GalleryEvent.IMAGE_CLICK).toCommand(ImageClickCommand);
			commandMap.map(GalleryEvent.CLOSE_PREVIEW).toCommand(ClosePreviewCommand);
Медиаторы состоят из пары классов Медиатор (наследуется от Mediator) - отображение (наследуется от Sprite):
Код AS3:
 			mediatorMap.map(MainPanelTile).toMediator(MainPanelTileMediator);
			mediatorMap.map(Preview).toMediator(PreviewMediator);
Все классы проинициализированы. Теперь посмотрим, как они взаимодействуют.

Первая команда (LoadAllCommand) запускается по событию Event.INIT, которое вызывается самим конфигуратором по завершению его работы. Она загружает все файлы и кладёт в модель.
Каждая команда выполняется через функцию execute.

LoadAllCommand.as:
Код AS3:
 package app.controller 
{
	import app.dicts.Constants;
	import app.events.GalleryEvent;
	import app.model.ImageModel;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.net.URLRequest;
	import robotlegs.bender.bundles.mvcs.Command;
 
	public class LoadAllCommand extends Command
	{
		public function LoadAllCommand() { }
 
		//--------------------------------------------------------------------------
		//
		// PUBLIC SECTION 
		//
		//--------------------------------------------------------------------------
		[Inject]
		public var imageModel:ImageModel;
 
		[Inject]
		public var dispatcher:IEventDispatcher;
 
		override public function execute():void
		{
			_fileList = Constants.FILES_LIST;
			_total = _fileList.length;
			var loader:Loader;
			for (var i:int = 0; i < _total; i++)
			{
				loader = new Loader();
				loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoadHandler);
				loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
				loader.load(new URLRequest(_fileList[i]));
			}
		}
 
		//--------------------------------------------------------------------------
		//
		// PRIVATE SECTION 
		//
		//--------------------------------------------------------------------------
		private var _fileList:Vector.<String>;
		private var _total:uint;
		private var _loaded:uint = 0;
		private var _images:Array = [];
 
		private function imageLoadHandler(event:Event):void
		{
			var info:LoaderInfo = LoaderInfo(event.currentTarget);
			_images[Constants.FILES_LIST.indexOf(info.url)] = info.content;
			info.loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, imageLoadHandler);
			info.loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
			_loaded++;
			if (_loaded >= _total)
			{
				imageModel.addImages(_images);
				dispatcher.dispatchEvent(new GalleryEvent(GalleryEvent.LOAD_COMPLETE));
			}
		}
 
		private function errorHandler(event:ErrorEvent):void
		{
			throw new Error("bad link or internet disconnect");
		}
	}
}
Весь цимес заключён вот здесь:
Код AS3:
 			if (_loaded >= _total)
			{
				imageModel.addImages(_images);
				dispatcher.dispatchEvent(new GalleryEvent(GalleryEvent.LOAD_COMPLETE));
			}
Сначала, загрузив все данные, команда кладёт их в модель. Затем диспатчит событие, которое (как видно из GalleryConfig) запускает следующую команду - CreateMainPanelCommand.

CreateMainPanelCommand.as:
Код AS3:
 package app.controller 
{
	import app.model.ImageModel;
	import app.view.MainPanelTile;
	import robotlegs.bender.bundles.mvcs.Command;
	import robotlegs.bender.extensions.contextView.ContextView;
 
	public class CreateMainPanelCommand extends Command
	{
		public function CreateMainPanelCommand() { }
 
		//--------------------------------------------------------------------------
		//
		// PUBLIC SECTION 
		//
		//--------------------------------------------------------------------------
		[Inject]
		public var imageModel:ImageModel;
 
		[Inject]
		public var contextView:ContextView;
 
		override public function execute():void
		{
			var tilesList:Vector.<MainPanelTile> = new Vector.<MainPanelTile>();
			var length:uint = imageModel.totalCount;
			for (var i:int = 0; i < length; i++)
			{
				tilesList[i] = new MainPanelTile(imageModel.cloneImage(i), i);
				tilesList[i].x = 10 + ((tilesList.length - 1) % COLUMN) * WIDTH;
				tilesList[i].y = 10 + int((tilesList.length - 1) / COLUMN) * HEIGHT;
				contextView.view.addChild(tilesList[i]);
			}
		}
 
		//--------------------------------------------------------------------------
		//
		// PRIVATE SECTION 
		//
		//--------------------------------------------------------------------------
		private static const COLUMN:uint = 4;
		private static const WIDTH:uint = 200;
		private static const HEIGHT:uint = 160;
	}
}
Эта команда создаёт по тайлу на каждое изображение. Обратите внимание, создаются именно тайлы, а их медиаторы, закреплённые за ними, инициализируются автоматом. Данные для тайлов можно подтянуть из imageModel, куда их предусмотрительно положила предыдущая команда.

MainPanelTile.as:
Код AS3:
 package app.view 
{
	import flash.display.Bitmap;
	import flash.display.Sprite;
 
	public class MainPanelTile extends Sprite
	{
		public function MainPanelTile(image:Bitmap, index:int) 
		{
			mouseChildren = false;
			buttonMode = true;
			_index = index;
			_template = new TileTemplate();
			addChild(_template);
 
			var width:int = _template.maskMc.width;
			var height:int = _template.maskMc.height;
			var diff:Number = Math.max(_template.maskMc.width / image.width, _template.maskMc.height / image.height);
			image.width *= diff;
			image.height *= diff;
			image.x = - image.width / 2;
			image.y = - image.height / 2;
			image.smoothing = true;
			_template.iconSlot.addChild(image);
			_template.iconSlot.mask = _template.maskMc;
		}
 
		//--------------------------------------------------------------------------
		//
		// PUBLIC SECTION 
		//
		//--------------------------------------------------------------------------
		public function get index():int
		{
			return _index;
		}
 
		public function destroy():void
		{
			removeChild(_template);
			_template = null;
		}
 
		//--------------------------------------------------------------------------
		//
		// PUBLIC SECTION 
		//
		//--------------------------------------------------------------------------
		private var _template:TileTemplate;
		private var _index:int;
	}
}
Медиатор выступает связывающим звеном между вьюшкой (MainPanelTile) и остальными компонентами. В нём уже предусмотрены initialize и destroy, которые нужно заоверрайдить.

MainPanelTileMediator.as:
Код AS3:
 package app.view 
{
	import app.events.GalleryEvent;
	import app.model.ImageModel;
	import flash.events.MouseEvent;
	import robotlegs.bender.bundles.mvcs.Mediator;
 
	public class MainPanelTileMediator extends Mediator
	{
		public function MainPanelTileMediator() { }
 
		//--------------------------------------------------------------------------
		//
		// PUBLIC SECTION 
		//
		//--------------------------------------------------------------------------
		[Inject]
		public var view:MainPanelTile;
 
		[Inject]
		public var imageModel:ImageModel;
 
		override public function initialize():void
		{
			eventMap.mapListener(view, MouseEvent.CLICK, clickHandler);
		}
 
		//--------------------------------------------------------------------------
		//
		// EVENT HANDLERS
		//
		//--------------------------------------------------------------------------
		private function clickHandler(event:MouseEvent):void
		{
			imageModel.indexClick = view.index;
			eventDispatcher.dispatchEvent(new GalleryEvent(GalleryEvent.IMAGE_CLICK));
		}
	}
}
Медиатор ссылается на вьюшку через переменную view (опять вездесущий [Inject]). Нам нужно слушать клик по тайлу, это объявляется следующим образом:
Код AS3:
 eventMap.mapListener(view, MouseEvent.CLICK, clickHandler);
Обработчик clickHandler пишет в модель индекс нажатого тайла и генерирует следующее событие - GalleryEvent.IMAGE_CLICK, которое открывает превью изображения через команду ImageClickCommand.

ImageClickCommand.as:
Код AS3:
 package app.controller 
{
	import app.model.ImageModel;
	import app.view.Preview;
	import flash.display.Bitmap;
	import robotlegs.bender.bundles.mvcs.Command;
	import robotlegs.bender.extensions.contextView.ContextView;
 
	public class ImageClickCommand extends Command
	{
		public function ImageClickCommand() { }
 
		//--------------------------------------------------------------------------
		//
		// PUBLIC SECTION 
		//
		//--------------------------------------------------------------------------
		[Inject]
		public var imageModel:ImageModel;
 
		[Inject]
		public var contextView:ContextView;
 
		override public function execute():void
		{
			var bitmap:Bitmap = imageModel.getImage();
			var preview:Preview;
			if (!imageModel.preview)
				preview = new Preview();
			else
				preview = imageModel.preview;
 
			preview.update(bitmap, imageModel.indexClick, imageModel.totalCount, contextView.view.stage);
			if (!imageModel.preview)
			{
				contextView.view.addChild(preview);
				imageModel.preview = preview;
			}
		}
	}
}
ImageClickCommand создаёт следующую вьюшку - Preview (или обновляет, если она уже есть).
Как и MainPanel, Preview состоит из 2 классов - собственно вью и медиатора.
Preview должен обрабатывать клики на 3 элемента - 2 кнопки и фон. Чтобы медиатор мог это сделать, даю к ним доступ через аксессоры.

Preview.as:
Код AS3:
 package app.view 
{
	import flash.display.Bitmap;
	import flash.display.Sprite;
	import flash.display.Stage;
 
	public class Preview extends Sprite
	{
		public function Preview() { }
 
		//--------------------------------------------------------------------------
		//
		// PUBLIC SECTION 
		//
		//--------------------------------------------------------------------------
		public function update(bitmap:Bitmap, index:int, totalCount:int, stage:Stage):void
		{
			if (_image && _image.parent)
				_image.parent.removeChild(_image);
			_image = null;
 
			_image = bitmap;
			_index = index;
			if (!_template)
			{
				_template = new Sprite();
				_template.graphics.beginFill(0x000000, 0.6);
				_template.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
				_template.graphics.endFill();
				addChild(_template);
 
				_btnBack = new BtnBackTemplate();
				_btnBack.buttonMode = true;
				_btnBack.x = 0;
				_btnBack.y = (stage.stageHeight - _btnBack.height) / 2;
				addChild(_btnBack);
 
				_btnNext = new BtnNextTemplate();
				_btnNext.buttonMode = true;
				_btnNext.x = stage.stageWidth - _btnNext.width;
				_btnNext.y = (stage.stageHeight - _btnNext.height) / 2;
				addChild(_btnNext);
			}
			_btnBack.alpha = _index > 0 ? 1 : 0.4;
			_btnNext.alpha = _index + 1 < totalCount ? 1 : 0.4;
 
			var diff:Number = Math.min(stage.stageWidth / _image.width, stage.stageHeight / _image.height);
			_image.width *= diff;
			_image.height *= diff;
			_image.smoothing = true;
			_image.x = (stage.stageWidth - _image.width) / 2;
			_image.y = (stage.stageHeight - _image.height) / 2;
			_template.addChild(_image);
		}
 
		public function get template():Sprite
		{
			return _template;
		}
 
		public function get btnBack():Sprite
		{
			return _btnBack;
		}
 
		public function get btnNext():Sprite
		{
			return _btnNext;
		}
 
		public function destroy():void
		{
			if (_btnBack)
			{
				_btnBack.parent.removeChild(_btnBack);
				_btnBack = null;
			}
			if (_btnNext)
			{
				_btnNext.parent.removeChild(_btnNext);
				_btnNext = null;
			}
			if (_image && _image.parent)
				_image.parent.removeChild(_image);
			_image = null;
			if (_template)
			{
				_template.parent.removeChild(_template);
				_template = null;
			}
		}
 
		//--------------------------------------------------------------------------
		//
		// PRIVATE SECTION 
		//
		//--------------------------------------------------------------------------
		private var _image:Bitmap;
		private var _template:Sprite;
		private var _btnBack:BtnBackTemplate;
		private var _btnNext:BtnNextTemplate;
		private var _index:int;
	}
}
Теперь медиатор может обрабатывать эти клики. На клики кнопок он генерирует событие GalleryEvent.IMAGE_CLICK с новым индексом, которое вновь вызывает команду ImageClickCommand.

PreviewMediator.as:
Код AS3:
 package app.view 
{
	import app.events.GalleryEvent;
	import app.model.ImageModel;
	import flash.events.MouseEvent;
	import robotlegs.bender.bundles.mvcs.Mediator;
 
	public class PreviewMediator extends Mediator
	{
		public function PreviewMediator() { }
 
		//--------------------------------------------------------------------------
		//
		// PUBLIC SECTION 
		//
		//--------------------------------------------------------------------------
		[Inject]
		public var view:Preview;
 
		[Inject]
		public var imageModel:ImageModel;
 
		override public function initialize():void
		{
			eventMap.mapListener(view.template, MouseEvent.CLICK, clickHandler);
			eventMap.mapListener(view.btnBack, MouseEvent.CLICK, backClickHandler);
			eventMap.mapListener(view.btnNext, MouseEvent.CLICK, nextClickHandler);
		}
 
		override public function destroy():void
		{
			view.destroy();
			view = null;
		}
 
		//--------------------------------------------------------------------------
		//
		// EVENT HANDLERS
		//
		//--------------------------------------------------------------------------
		private function clickHandler(event:MouseEvent):void
		{
			eventDispatcher.dispatchEvent(new GalleryEvent(GalleryEvent.CLOSE_PREVIEW));
		}
 
		private function backClickHandler(event:MouseEvent):void
		{
			if (event.currentTarget.alpha < 1)
				return;
			imageModel.indexClick--;
			eventDispatcher.dispatchEvent(new GalleryEvent(GalleryEvent.IMAGE_CLICK));
		}
 
		private function nextClickHandler(event:MouseEvent):void
		{
			if (event.currentTarget.alpha < 1)
				return;
			imageModel.indexClick++;
			eventDispatcher.dispatchEvent(new GalleryEvent(GalleryEvent.IMAGE_CLICK));
		}
	}
}
Клик по фону генерирует событие GalleryEvent.CLOSE_PREVIEW, которое вызывает команду закрытия превью и возврат к главному меню.

ClosePreviewCommand.as:
Код AS3:
 package app.controller 
{
	import app.model.ImageModel;
	import robotlegs.bender.bundles.mvcs.Command;
	import robotlegs.bender.extensions.contextView.ContextView;
 
	public class ClosePreviewCommand extends Command
	{
		public function ClosePreviewCommand() { }
 
		//--------------------------------------------------------------------------
		//
		// PUBLIC SECTION 
		//
		//--------------------------------------------------------------------------
		[Inject]
		public var imageModel:ImageModel;
 
		[Inject]
		public var contextView:ContextView;
 
		override public function execute():void
		{
			contextView.view.removeChild(imageModel.preview);
			imageModel.preview = null;
		}
	}
}
Теперь можно вывести окончательный код модели. Модель - класс, хранящий текущее представление данных. Поскольку проект маленький, модель у нас одна. Она представляет следующий функционал:

- позволяет записать загруженные битмапы изображений;
- отдаёт по индексу битмапу или её клон (поскольку битмапы могут выводиться на экран несколько раз);
- принимает и отдаёт индекс последнего нажатого тайла;
- хранит спрайт Preview, доступ к которому необходим из разных классов. Возможно, это неправильно, но не придумал, где ещё его хранить.

ImageModel.as:
Код AS3:
 package app.model 
{
	import app.view.Preview;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
 
	public class ImageModel
	{
		public function ImageModel() { }
 
		//--------------------------------------------------------------------------
		//
		// PUBLIC SECTION 
		//
		//--------------------------------------------------------------------------
		public function addImages(value:Array):void
		{
			if (!_images)
				_images = new Vector.<Bitmap>();
			for (var i:int = 0; i < value.length; i++)
			{
				_images.push(value[i]);
			}
		}
 
		public function get indexClick():int
		{
			return _indexClick;
		}
 
		public function set indexClick(value:int):void
		{
			_indexClick = value;
		}
 
		public function cloneImage(i:int):Bitmap
		{
			var data:BitmapData = new BitmapData(_images[i].width, _images[i].height, false);
			data.draw(_images[i]);
			var cloneData:BitmapData = data.clone();
			var cloneBitmap:Bitmap = new Bitmap(cloneData);
			return cloneBitmap;
		}
 
		public function getImage():Bitmap
		{
			return _images[_indexClick];
		}
 
		public function get totalCount():int
		{
			return _images.length;
		}
 
		public function get preview():Preview
		{
			return _preview;
		}
 
		public function set preview(value:Preview):void
		{
			_preview = value;
		}
 
		//--------------------------------------------------------------------------
		//
		// PRIVATE SECTION 
		//
		//--------------------------------------------------------------------------
		private var _images:Vector.<Bitmap>;
		private var _indexClick:int;
		private var _preview:Preview;
	}
}
Часть 2. Отличия robotlegs 1.5.2 и 2.2.1
- библиотечный Context создаётся в пользовательском (ранее пользовательский Context наследовался от библиотечного);
- ранее все классы мапились в моём Context, теперь для этого есть Config, добавляющийся через функцию context.configure(). Синтаксис поменялся до неузнаваемости;
- ранее первая команда запускалась на библиотечное событие ContextEvent.STARTUP_COMPLETE, теперь событие нужно родить самому;
- ранее модель наследовалась от класса Actor, который тупо исчез;
- ранее contextView и eventDispatcher уже были доступны в командах, моделях и медиаторах, теперь их нужно подключать через [Inject].

Часть 3. Плюсы и минусы.
Плюсы по сравнению с pureMVC:
+ намного проще разобраться как применить либу вцелом (моё субъективное мнение);
+ намного проще доступ к stage и глобальным данным вообще;
+ общение через кошерные человеческие ивенты, а не странные обсерверы.
Минусы вообще:
- огромная разница между версиями либы, что может вылезти боком тому, кто захочет обновить проект;
- каждый медиатор состоит из 2 классов.

А выводы пусть каждый делает сам
Вложения
Тип файла: zip robot1.5.2.zip (131.1 Кб, 164 просмотров)
Тип файла: zip robot2.2.1.zip (305.3 Кб, 169 просмотров)
Всего комментариев 15

Комментарии

Старый 22.07.2014 16:18 Babylon вне форума
Babylon
 
Аватар для Babylon
Сигналов не хватает.
Старый 22.07.2014 16:34 alatar вне форума
alatar
 
Аватар для alatar
Старый 22.07.2014 16:37 alatar вне форума
alatar
 
Аватар для alatar
Цитата:
- каждый медиатор состоит из 2 классов.
Это вообще о чем, какие два класса?
Если об этом:
Цитата:
Медиаторы состоят из пары классов Медиатор (наследуется от Mediator) - отображение (наследуется от Sprite)
то, пардон, медиатор состоит из одного класса, второе, как вы сами заметили — отображение (aka view).
Старый 22.07.2014 17:33 PainKiller вне форума
PainKiller
 
Аватар для PainKiller
Начал читать сразу резануло глаза
Цитата:
После этого происходит магия, и переменная dispatcher становится доступной для использования во всём классе.
При чем тут магия?
Старый 22.07.2014 17:35 fljot вне форума
fljot
Кто отдаёт предпочтение командам вместо более толстых контроллеров-сервисов (которые живут подольше команд) – черкните пару строк, почему?
Старый 22.07.2014 18:10 LifeIsRhythm вне форума
LifeIsRhythm
А может кто-нибудь объяснить, для каких целей предназначен RL2? Что на нем делать нельзя?
И расскажите пожалуйста, что происходит за кулисами, когда я обращаюсь из объекта к инжектируемому
свойству ( в данном примере это модель ) ?
Обновил(-а) LifeIsRhythm 22.07.2014 в 18:52
Старый 22.07.2014 21:47 dimarik вне форума
dimarik
 
Аватар для dimarik
Прошу прощения что не по профилю обсуждения, но зацепился мой взгляд.

Код AS3:
private function imageLoadHandler(event:Event):void
{
    var info:LoaderInfo = LoaderInfo(event.currentTarget);
    info.loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, imageLoadHandler);
    info.loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
}
В приведенном листинге присутствует конвертация LoaderInfo() взамен приведения event.currentTarget as LoaderInfo. event.currentTarget для объектов, не входящих в подмножество DispayObject будет соответствовать event.target и идеологически необходимо использовать именно его. Как следствие, ваш info это ни что иное как ссылка на info.loader.contentLoaderInfo, т. е. на самого себя через Красную Тымь. В общем, принимайте такой вариант.
Код AS3:
private function imageLoadHandler(event:Event):void
{
    var info:LoaderInfo = event.traget as LoaderInfo;
    info.removeEventListener(Event.COMPLETE, imageLoadHandler);
    info.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
}
Старый 22.07.2014 22:39 Rembrant вне форума
Rembrant
 
Аватар для Rembrant
PainKiller
Цитата:
При чем тут магия?
так как сам не совсем понял, как работает Inject. работает, и всё тут.

dimarik
Цитата:
В общем, принимайте такой вариант.
Никогда не думал, что моя и Ваша конструкции отличаются по сути.
Принимаю)
Старый 22.07.2014 23:32 dimarik вне форума
dimarik
 
Аватар для dimarik
Я не навязываю свою точку зрения, отнюдь. Пишите как вам удобнее. Вам же с этим жить, а не мне.
Старый 23.07.2014 11:45 Rembrant вне форума
Rembrant
 
Аватар для Rembrant
dimarik, прочитал с утра на свежую голову - дошло.
Старый 28.07.2014 16:25 nOobCrafter вне форума
nOobCrafter
Цитата:
- огромная разница между версиями либы
Ну как бы это разные мажор версии, конечно отличия могут быть довольно большими и про обратную совместимость речь особо не идет, но миграция с 1.х на 2.х обещали довольно простую.
Ну и личные впечатления, 2.х версия имеет больше различного сахара, более прозрачна в конфигурировании и исполнении, имеет гибкую систему расширений.
Кстати сразу рекомендую обратить внимание на расширение Macrobot.
Старый 02.09.2014 04:23 fljot вне форума
fljot
Кстати, не повторяйте частую ошибку
http://knowledge.robotlegs.org/discu...in-a-wrong-way
Старый 04.09.2014 20:30 dimarik вне форума
dimarik
 
Аватар для dimarik
Цитата:
Кстати, не повторяйте частую ошибку
Не везет тебе с тимлидами.
Старый 08.09.2014 17:18 Rembrant вне форума
Rembrant
 
Аватар для Rembrant
fljot
у меня туговато с английским... можно в двух словах, о чём там?
Старый 11.09.2014 11:02 Cybo вне форума
Cybo
Там говориться о том, что многие разработчики используют названия событий в ИМПЕРАТИВНОЙ форме, т.е. MyEvent.СДЕЛАТЬ_ЧТО_НИБУДЬ. А правильно, названия событий писать в ПАССИВНОЙ форме, например, MyEvent.ЧТО_ТО_СЛУЧИЛОСЬ. Т.е. привязывать названия событий НЕ к действиям после события, а к тем действиям, которые родили это событие.
 
Последние записи от Rembrant

 


Часовой пояс GMT +4, время: 18:30.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.