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

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

Рейтинг: 4.79. Голосов: 19.

MVC, часть 1: про дубовый стол и сиськи

Запись от Psycho Tiger размещена 30.10.2010 в 02:36
Обновил(-а) Psycho Tiger 14.12.2010 в 18:10

[Что-то очень глючил редактор, где то возможны нестыковки - текст порой просто удалялся. Замечания пишите в комменты. Спасибо]

...и вот появился на свет гений. Истинный Разработчик. Луч света падает на него, а клавиатура сокрушается под ударами его пальцев... Сейчас он сядет и сделает шедевр, в ритмах Вивальди извлекая звуки от щелчков мышки и ритмичных ударов о клавиатуре...

Думайте это о Вас? Обо мне? Пфф... Это Вам не сага о Горце. Тут придется включить свою голову. Ну или хотя бы сделать вид. Как бы то ни было - купите виски и откиньтесь на спинку кожаного кресла, положив свои ноги в ботинках из крокодиловой кожи на стол из столетнего дуба. Да-да, вы не ослышались. MVC - это действительно круто. Соплякам тут не место )

Мне всегда вот в научных статьях, учебниках по квантовой физике и статьях на википедии не нравилось одно - сухость материала. Ну пришел Шредингер, сказал что нашел универсальное уравнение в материи в целом - и понеслись иероглифы. Ну вот как это следует вообще понимать? Тут тоньше надо. Не спугнуть читателя, объяснять всё простым языком... Тут тренд Дисковери уловил, конечно. Поэтому давайте-ка я расскажу вам о трёх буквах.

Готовы? Отлично, так рад видеть на Ваших лицах заинтересованность - вот оно, "эм вэ цэ" да ещё и языком художественным текстом, где возможно. Только сразу огорчу - про дубовые столы я погорячился. Точнее, не погорячился, а совсем соврал. Это полная чушь, что MVC что-то там даёт. Да-да, я вас сильно обманул, но обещаю, что больше так делать не буду, а вы мне взамен обещайте что будете слушать меня внимательно. Договорились? Договорились. Дак вот, MVC - это просто инструмент, он не сделает из Вас ни "тру-флешера", ни человека способного на что-то большее, чем он умел до этого. Скажу больше, удобство использования вы ощутите... ну после нескольких недель работы. Это как накачать пресс - жирок то родной, булочки вкусные, а тренажеры не манят. Зато потом сверкая прессом перед девочками на пляже... ну вы поняли. Не испугались? Тогда вперёд )

Начнем, пожалуй, с истории среднестатистического флеш-разработчика. Речь, конечно же, пойдёт о человеке растущим на флеше с 0, а не матёрым Java`ером, который решил переквалифицироваться.

Сперва разработчик начинает писать свой код в кадрах/в одном классе. Он не понимает, зачем создавать другие классы, ведь всё можно написать здесь - и оформить функцией - то есть замыканием. Некоторые о приёме замыкания не знают - и слава богу - и пишут в методах.
Наступает момент, когда кода становится слишком много и под давлением общественности человек начинает делать попытки создавать другие классы. И тут же чувствует себя скованным - как же получить глобальную переменную... В следствии чего в конструктор пихает всё что только может. А ещё лучше - ссылку на класс, который его и создал. В итоге Main порождает пятерку других классов. И все знают всё о Main.
Потом человек понимает, что так передавать - крайне неэффективно. И начинает использовать синглтон. Ну как синглтон... Он думает, что это синглтон. На самом деле - просто набор статический методов и переменных. Ну должен же быть глобальный контроль!

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

И вот только потом, через много времени он чувствует себя готовым. Готовым к большим открытиям и большим наградам. И виднеются на горизонте три большие, заглавные буквы - M, символизирующие Молодец разработчику, V, символизирующее пятерку за архитектуру и C - символизирующее Сиськи, которых порой так не хватает рядом во время длительной разработки. Ну, это для меня. MVC - у каждого своё. Вроде бы очевидно, что от MVC со временем не так то просто отказаться.


...Затянулось начало. Перейдём к делу.
Чтобы было сразу понятней - сразу же введем пример. Предположим, у нас есть герой у которого есть 3 вида оружия. Вид игры - сверху.
Рассмотрим отдельно все части:
M - Model. Модель. Хранит данные, которые нужны триаде (MVC). Это - координаты игрока в мире, текущие оружие в руках, количество здоровья, количество боеприпасов. Остальные данные - например количество крови хлыщущее из его вены в модели не хранятся.

V - View. Вьюшка. Отображалка. Занимается всем тем, что видит и слышит пользователь. Хранит в себе как раз количество крови, которое из игрока хлыщет, само изображение игрока, создаёт звуки выстрелов... Ну вы поняли. Это всё, что вообще есть на экране.

C - Controller. Контроллер. Он занимается логикой всей триады. Именно он обрабатывает нажатие клавиш и меняет данные в модели, записывая туда новые координаты игрока. Именно он разрешает игроку стрелять и меняет у него оружие.

Всё понятно? Не пытайтесь проводить грань и понять взаимодействие между ними - просто определитесь, кто что делает.

Сейчас я дам вам картинку, нагло взятую где то из интернета.


Какая прелесть, правда? Давайте разберемся. Сплошными линиями показаны жесткие связи между трио - то есть у контроллера есть прямая ссылка на модель и на вьюшку, а у вьюшки на модель. Штрихованными же показано кто кого слушает - контроллер слушает вьюшку, а вьюшка модель. Что такое "слушает" - ниже, на примере каждого.

Пример с игрой и человечком сверху был удачным для объяснения идеи текстом, но мне кажется для практической реализации нужно взять пример попроще. Давайте сделаем совсем элементарный пример: несколько квадратиков, все разных цветов. При этом есть одна стрелочка, которая указывает на один из квадратов. По клику стрелочка указывает на случайный квадратик, а каждые 3 секунды цвета у квадратов меняются. Это игра будет для детей дошкольного возраста: они должны будут произносить вслух цвет, на который указывает стрелочка, а воспитатель скажет, правильно или нет.
Итак. Сперва мы должны создать Главный контроллер - он всегда самый главный в любом приложении. У нас будет всего один контроллер, одна модель и одна вьюшка - поэтому контроллер главный, и по совместительству единственный. Контроллеру нужно знать, куда добавлять всю прелестную графику? Нужно. Поэтому ему нужен иметь какую-то точку привязки для графики - DisplayObjectContainer. Где её взять? Это - ваш класс Main, который базовый. Как создать главный контроллер? В Main, в конструкторе или в обработчике события Event.ADDED_TO_STAGE нужно написать примерно следующее:
Код AS3:
new BaseController(this);
Мы просто создали этот контроллер и передали ссылку на себя - то есть на то место, где будет скапливаться вся графика. Нам даже не нужно сохранять ссылку на главный контроллер!
Код класса BaseController:
Код AS3:
package
{
	import flash.display.DisplayObjectContainer;
 
	public class BaseController
	{
		private var _host:DisplayObjectContainer;
		private var _model:Model;
		private var _view:View;
 
		public function BaseController(host:DisplayObjectContainer)
		{
			super();
			_host = host;
			_model = new Model();
			_view = new View(_model);
 
		}
 
	}
 
}
Что мы сделали? Мы просто в конструкторе сразу же создали и модель, и вьюшку.
Давайте напишем модель. Сперва нужно понять, что должно быть в модели. В модели должны быть данные, которые нужны всей триаде. Это - цвета всех квадратов и номер квадрата, на который указывает стрелочка. "А как же графика для стрелочки, размеры квадрата, расстояние между ними и всё остальное?" - воскликнет читатель. Нет, эти данные не должны хранится в модели. Вся графика, все звуки и всё остальное - это забота вьюшки, в этом и прелесть: сегодня у меня на экране человек, а завтра киборг. При этом я переписываю только отображение, не трогая контроллер и модель, тем самым не "ломая" логику. Размер прямоугольников - не нужен в контексте этой задачи - нам плевать на форму, хоть квадратная, хоть скругленная. Нам так же плевать на позиции - хоть синусоидально, хоть по прямой. На логику это не влияет. Нам просто нужно выводить на экран какие-то цветные элементы и помечать их. Отсюда всплывает очередная прелесть - мы можем не сильно заботится о том, что творится на экране, оставив это на "потом". Будь другой контекст - например, если бы нужно было отгадать размер в пикселах этой фигуры - то эти данные попали бы в модель. Аналогично и с формой, и с расположением. Проще говоря, в модели хранятся значимые данные в данной задаче. А на фоне гусей или океана это происходит - программу не колышет.

Итак, нам нужно хранить в модели массив цветов и номер прямоугольника, на который указывает стрелка. При этом при изменении информации в модели неплохо было бы заявить всем желающим, что данные изменились - неплохо бы их обновить. Это означает, что модель должна испустить событие о том, что она изменилась. Делается это GoF паттерном Observer, но не пугайтесь: обычная событийная флешевая событийная модель реализует именно его, поэтому нам совсем не стоит об этом беспокоится. При обновлении информации есть 2 подхода: push и pull. При обновлении информации мы генерируем событие о том, что что-то изменилось. Представим, что это событие кто-то поймал. В событии может содержаться вся информация о том, что же изменилось - такой подход называется push - мы проталкиваем с событием всё что нужно обновить. Другой подход - pull - значит "тяни". В таком случае события носят нотификационный характер - что-то вроде "Эй парень, число народу в игре обновилось.". А сколько теперь онлайн - это событие не скажет. И в таком случае эти данные приходится "тянуть" с модели явно. Я использую оба подхода, оба подхода хороши. Но конкретно сейчас я ограничусь pull-подходом. Кстати, событийное поведение добавляет ещё одно удобство, одно из главных - если у нас в 5 разных местах показывается, например, баланс игрока - то при изменении баланса в одном месте он должен поменяться во всех.
Но тут всплывает проблема: поменяв номер прямоугольника, на который указывает стрелочка вызовется сеттер, который испустит событие об изменении. Но в случае с массивом всё не так: чтобы вызвать сеттер у массива нужно будет переопределить на него ссылку, что недопустимо: нам нужно просто менять элементы массива, но не ссылку на него. Решений у проблемы несколько. Например, самый извращенный - это унаследовать модель от Proxy, определив там поведение для [], попутно реализовав ей IEventDispatcher. Можно, например, сделать метод setElement, в теле которых и генерировать событие об изменении. Можно в модели добавить метод "сделай событие пожалуйста, что ты изменилась" и дёргать его. Но немного подумав вспоминаем, что модель мы меняем в контроллере. А в контроллере мы имеем полный контроль над вьюшкой. Поэтому в этом случае на мой взгляд самым лучшим решением будет явно вызвать метод у вьюшки после того как закончится изменение модели.
Код Model:
Код AS3:
package  
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
 
	[Event(name="change", type="flash.events.Event")]
	public class Model extends EventDispatcher implements IReadableModel
	{
 
		private var _pointer:int = 0;
		public var colors:Array = [];
		public function Model() 
		{
			super();
		}
 
		public function get pointer():int { return _pointer; }
 
		public function set pointer(value:int):void 
		{
			if (_pointer == value) return;
			_pointer = value;
			super.dispatchEvent(new Event(Event.CHANGE));
		}
 
	}
 
}
Теперь сделаем вот такой вот финт в голове: абстрагируемся от трио и посмотрим только на модель. Просто храним данные, по возможности говорим всем желающим событием о том, что данные изменились. Ничего сложного, ведь так?

Итак, теперь View. Как мы поняли ранее, у View есть прямая ссылка на Model, в итоге нам нужно всего лишь визуализировать эти данные.
Код AS3:
package  
{
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
 
	public class View extends Sprite 
	{
		private var _model:Model;
		private var _squares:Array;
		private var _pointer:Shape;
 
		public function View(model:Model) {
			super();
			_model = model;
			 //здесь будем хранить ссылки на созданные графические объекты
			_squares = [];
			//это типа стрелочка
			_pointer = new Shape(); 
			_pointer.graphics.beginFill(0x00FF00);
			//круглая такая стрелочка
			_pointer.graphics.drawCircle(0, 0, 30); 
			_pointer.y = 100;
			_pointer.graphics.endFill();
 
			super.addChild(_pointer);
 
			//вызываем обработчик как будто-бы модель изменилась. Это нужно чтобы указатель
			//сразу встал на нужный квадрат
			onPointerChange(null);
 
			 //подписались на изменение модели
			_model.addEventListener(Event.CHANGE, onPointerChange);
		}
 
 
		public function updateSquares():void {
			//поменялись цвета - удаляем все старые прямоугольники
			var i:int = _squares.length;
			while (i--) super.removeChild(_squares.pop());
			//рисуем новые
			i = _model.colors.length;
			while (i--) {
				var shape:Shape = new Shape();
				shape.graphics.beginFill(_model.colors[i]);
				shape.graphics.drawRect(0, 0, 50, 50);
				shape.graphics.endFill();
				shape.x = 100 * i;
				_squares.push(shape);
				super.addChild(shape);
			}
		}
 
		private function onPointerChange(event:Event):void {
			_pointer.x = 100 * _model.pointer;
		}
 
	}
 
}
Мы рисуем квадраты - по цветам из массива, который хранится в модели и стрелочку, которая после конца кризиса набрала килограммов и стала круглой, заставляя её указывать на какой-то из квадратов. Какой - всё так же заявлено в модели.
Абстрагируемся. Нам сообщают событиями о том, что модель изменилась. Если мы получили такое сообщение - меняем изображение, чтобы быть актуальным каким-то данным, которые есть в модели. Попутно имеем паблик метод updateSquares, который будет вызван кем-то сверху, когда нужно обновить квадраты. Если не думать о трио в целом, а только об одном элементе - всё очень просто.
Резюме. Мы имеем что-то, что предоставляет нам данные и говорит, когда данные поменялись. На основе этого мы строим изображение. Всё просто? Отлично. Теперь связываем в голове модель и вьюшку. Связываем, думаем.

Готовы продолжать? Теперь контроллер.
Задача контроллера - менять модель. Просто писать в неё данные. Абстрагируемся вновь. Мы просто делаем какую-то логику, и пишем её в объект, не задумываясь о том что происходит дальше. Но ещё нам нужно вот что сделать в контроллере: добавить вьюшку в дисплай лист - т.е. просто сделать addChild к тому, что мы передали в конструктор главному контроллеру. По условию задачи менять каждые 3 секунды цвета. Что-ж, ничего сложного! Делаем:
Код AS3:
package  
{
	import flash.display.DisplayObjectContainer;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
 
	public class BaseController 
	{
		private var _host:DisplayObjectContainer;
		private var _model:Model;
		private var _view:View;
 
		public function BaseController(host:DisplayObjectContainer) 
		{
			super();
			_host = host;
			_model = new Model();
			_view = new View(_model);
 
			//создали таймер и запустили
			var _timer:Timer = new Timer(3000);
			_timer.addEventListener(TimerEvent.TIMER, onTimer);
			_timer.start();
 
			//сразу же вызвали обработчик, чтобы сразу при запуске забить массив
			//случайными квадратами
			onTimer(null);
 
			//добавили в дисплай лист - чтобы мы смогли увидеть работу вьюшки
			host.addChild(_view);
		}
 
		private function onTimer(event:TimerEvent):void 
		{
			//забиваем модель случайными цветами
			var i:int = 5;
			while (i--) {
				_model.colors[i] = int(Math.random() * 0xFFFFFF);
			}
 
			//говорим, что мы изменили цвета
			//это как раз тот момент из за невозможности вызова геттера
			_view.updateSquares();
		}
 
	}
 
}
И снова пытаемся представить контроллер как нечто "не связанное" с моделью и вьюшкой логически. Да-да, мы уже абстрагировались ещё перед написанием, но давайте не ленится. Если у вас получается, то он снова кажется простым - всего лишь меняем массив в каком-то объекте каждые 3 секунды. После этого пытаемся представить целостную картину, но это не всё. Мы не сделали интерактивность: стрелка (в нашем случае это круг) всегда будет указывать в одно место, а нам же необходимо чтобы стрелочка меняла положение на случайное по клику. Напоминаю, что это положение находится в модели.
Как это сделать? Наверное вам в голову лезет мысль - в контроллере отлавливать клик и менять модель. Нет, это не совсем правильно: это лепка программы "под конкретный вариант", а это как раз то, против чего создано MVC. Пользователь с чем взаимодействует? Только с вьюшкой. Он не может кликнуть по модели или по контроллеру - он кликает по экрану, что по сути является вьюшкой. Значит клик должна обрабатывать вьюшка. При этом это слишком связано, что именно по клику: сегодня по клику, завтра по нажатию клавиши, а послезавтра вообще по голосовой команде. Вьюшка должна сообщить о том, что надо бы поменять стрелочку - а уж отчего вьюшка так решила знает только она сама. В итоге во View дописываем функционал, что по клику диспатчим какое-то событие, которое слушает контроллер. Я опять буду использовать событие Event.CHANGE - поначалу могут возникнуть сложности - как же так, мы ведь его уже используем в модели - но это здорово развивает абстракцию. В реальных проектах типов событий у меня очень часто больше 30-40, тут, конечно, одним Event.CHANGE не обойтись и я делаю свой класс, расширяющий Event. Однако, какой случай - такой и инструмент, поэтому здесь Event.CHANGE.
Код AS3:
package  
{
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
 
	[Event(name="change", type="flash.events.Event")]
	public class View extends Sprite 
	{
		private var _model:Model;
		private var _squares:Array;
		private var _pointer:Shape;
 
		public function View(model:Model) {
			super();
			_model = model;
			 //здесь будем хранить ссылки на созданные графические объекты
			_squares = [];
			//это типа стрелочка
			_pointer = new Shape(); 
			_pointer.graphics.beginFill(0x00FF00);
			//круглая такая стрелочка
			_pointer.graphics.drawCircle(0, 0, 30); 
			_pointer.y = 100;
			_pointer.graphics.endFill();
 
			super.addChild(_pointer);
 
			//вызываем обработчик как будто-бы модель изменилась. Это нужно чтобы указатель
			//сразу встал на нужный квадрат
			onPointerChange(null);
 
			 //подписались на изменение модели
			_model.addEventListener(Event.CHANGE, onPointerChange);
 
			//нам должен быть доступен stage
			super.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
		}
 
		private function onAddedToStage(event:Event):void 
		{
			super.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
			//подписались на заветный click
			super.stage.addEventListener(MouseEvent.CLICK, onClick);
		}
 
		private function onClick(event:MouseEvent):void 
		{
			//и выпустили событие
			super.dispatchEvent(new Event(Event.CHANGE));
		}
 
		public function updateSquares():void {
			//поменялись цвета - удаляем все старые прямоугольники
			var i:int = _squares.length;
			while (i--) super.removeChild(_squares.pop());
			//рисуем новые
			i = _model.colors.length;
			while (i--) {
				var shape:Shape = new Shape();
				shape.graphics.beginFill(_model.colors[i]);
				shape.graphics.drawRect(0, 0, 50, 50);
				shape.graphics.endFill();
				shape.x = 100 * i;
				_squares.push(shape);
				super.addChild(shape);
			}
		}
 
		private function onPointerChange(event:Event):void {
			_pointer.x = 100 * _model.pointer;
		}
 
	}
 
}
Это полный код View. Просто дописали, что по клику происходит испускание события Event.CHANGE.
Теперь немного перепишем контроллер:
Код AS3:
package  
{
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
 
	public class BaseController 
	{
		private var _host:DisplayObjectContainer;
		private var _model:Model;
		private var _view:View;
 
		public function BaseController(host:DisplayObjectContainer) 
		{
			super();
			_host = host;
			_model = new Model();
			_view = new View(_model);
 
			//создали таймер и запустили
			var _timer:Timer = new Timer(3000);
			_timer.addEventListener(TimerEvent.TIMER, onTimer);
			_timer.start();
 
			//сразу же вызвали обработчик, чтобы сразу при запуске забить массив
			//случайными квадратами
			onTimer(null);
 
			//добавили в дисплай лист - чтобы мы смогли увидеть работу вьюшки
			host.addChild(_view);
 
			//подписались на событие, по которому нужно изменить модель
			_view.addEventListener(Event.CHANGE, onViewChange);
		}
 
		private function onViewChange(event:Event):void 
		{
			//просто случайная позиция для стрелочки
			_model.pointer = Math.random() * 5;
		}
 
		private function onTimer(event:TimerEvent):void 
		{
			//забиваем модель случайными цветами
			var i:int = 5;
			while (i--) {
				_model.colors[i] = int(Math.random() * 0xFFFFFF);
			}
 
			//говорим, что мы изменили цвета
			//это как раз тот момент из за невозможности вызова геттера
			_view.updateSquares();
		}
 
	}
 
}
Тут тоже всё банально и просто - как только поймали событие Event.CHANGE от View - сразу же поменяли модель, которая в свою очередь побудила измениться отображению. Такой круговорот получится - View - Controller - Model - View. Забавно, правда?

Теперь пролистните вверх и посмотрите снова на картинку и вновь перечитайте часть, где я рассказывал про связи между M, V и C (Model, View и Controller). Теперь всё куда понятней, не правда ли?

Но и это не всё.
View не может изменять Model, как вы уже поняли, а у нас может. Как это исправить? Вью нужно передавать не саму модель, а только интерфейс, в которым "порезаны" все set методы. Например, в нашем случае такой:
Код AS3:
package  
{	
	public interface IReadableModel 
	{
		function get pointer():int; 
		function get colors:Array;
	}
 
}
(необходимо будет добавить геттер colors в Model)
Однако, мы всё равно можем изменить элемента массива colors. Можно, конечно, придумать метод getElementAt, который бы лез в массив и возвращал элемент на заданной позиции, тем самым запретив изменять элементы массива... однако запрет на изменение модели не имеет другого характера, кроме как "защиты от дурака/запарки", чтобы случайно вы сами не поменяли модель. Мне не было бы стыдно оставить интерфейс в виде, который я привёл чуть выше - если вы не доверяете себе или людям, с которыми работаете - пишите метод. Это - инструмент, и он должен подстраиваться под вас, а не вы под него. Не стесняйтесь смотреть на картинку - она сильно помогает первое время. Если она даже сейчас кажется вам сложной - не смотрите на неё, а читайте текст и рисуйте эту картинку у себя на бумажке. Не ленитесь, это действительно помогает.

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

Вторая часть.
Всего комментариев 231

Комментарии

Старый 17.02.2011 19:11 alatar вне форума
alatar
 
Аватар для alatar
BlooDHounD, а куда он у вас делся? Или вы переход на второй кадр делаете?
Старый 17.02.2011 20:04 BlooDHounD вне форума
BlooDHounD
 
Аватар для BlooDHounD
эээ ... никуда не делся. удалился. а как без перехода на второй кадр инитироваться? и причём тут это?
Старый 18.02.2011 02:14 alatar вне форума
alatar
 
Аватар для alatar
В смысле как без перехода инициироваться? Для инициализации переход не нужен. Ну и сам класс который выполняет роль прелоадера и будет классом флешки, куда ж он удалится? Флешка же не может быть не визуальной.
Старый 18.02.2011 02:15 alatar вне форума
alatar
 
Аватар для alatar
Даже если сделать переход на второй кадр это ничего не изменит.
Старый 18.02.2011 03:05 BlooDHounD вне форума
BlooDHounD
 
Аватар для BlooDHounD
не нужен? тогда как инитиализуются все остальные классы? вы считаете что моя религия запрещает мне удалить прелоадер после того как он отработал?
Старый 18.02.2011 03:40 alatar вне форума
alatar
 
Аватар для alatar
Цитата:
тогда как инитиализуются все остальные классы?
Ну как обычно getDefinitionByName("BaseController")...
Цитата:
вы считаете что моя религия запрещает мне удалить прелоадер после того как он отработал?
Видимо мы говорим о разных вещах. Я подразумевал под прелоадером factoryClass.
Старый 18.02.2011 11:39 incvizitor вне форума
incvizitor
 
Аватар для incvizitor
alatar, можно забрать stage у factoryClass, а потом удалить его. Добавлять всё не в factoryClass, а прямо на сцену. (Если я правильно понял о чем Вы)
Старый 18.02.2011 12:27 alatar вне форума
alatar
 
Аватар для alatar
Да, действительно.
Старый 18.02.2011 16:10 BlooDHounD вне форума
BlooDHounD
 
Аватар для BlooDHounD
alatar, getDefinitionByName - это конечно замечательно, но откуда он возьмётся без перехода на второй кадр? я тоже подразумевал factoryClass. он какой-то особенный?
Старый 18.02.2011 18:08 alatar вне форума
alatar
 
Аватар для alatar
Мда... пора отдохнуть, что-то я торможу и несу ахинею.
Старый 28.11.2011 05:49 imena вне форума
imena
Здравствуйте! Все пытаюсь разобраться с MVC. Прочел ваши мысли и многое прояснилось, за что спасибо огромное.
Никак не могу понять кто грузит картинки. К примеру, у меня есть НЕКИЙ_ОБЪЕКТ, в который я передавал картинку и потом я просто делал addChild(НЕКИЙ_ОБЪЕКТ). ПО МВЦ я создаю объект в контроллере, отправляю информацию о созданном объекте в модель. Модель оповещает вьюшку что был добавлен новый объект. Откуда вьюшка берет графическое представление нашего объекта? Она отдельно грузит? Т.е. если у нас разные объекты, например, домик, ведро, какашка... все они являются объектами и размещаются на экране. Но откуда вьюшка берет картинки для всех этих домиков, ведер....? Как я понял, сами данные об объектах(если у нас есть функция сохранения) мы грузим в контроллере. Да?
И еще вопрос, если вьюшка сама откуда то грузит графику, то получается что если у нас есть объект ДОМИК, то в нем будет храниться только значения положения на экране и свойства этого домика, а картинку потом вьюшка прицепит?

Заранее спасибо за ответ
Старый 28.11.2011 11:13 incvizitor вне форума
incvizitor
 
Аватар для incvizitor
картинки грузит въюшка, так как другая въюшка может быть и без картинки. Допусти есть такой класс flash.display.Loader, указываете координаты и говорите грузить какой ни будь файл. Остальное он сам сделает. Правда я бы не советывал использовать именно Loader, лучше посмотрите вот это
Старый 28.11.2011 14:57 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Хм... Если картинка используется несколько раз - то она должна лежать в модели. Ну и складываться в модель соответствующим контроллером. Ибо что загрузить и куда положить - это логика, а за логику отвечают как раз контроллеры.
Старый 28.11.2011 15:11 imena вне форума
imena
Но в моделе не м.б. картинки, т.к. завтра картинка может поменяться же или я опять все напутал? Как я понял, в моделе даже не стоит хранить ширину и высоту картинки.
Старый 28.11.2011 15:13 fish_r вне форума
fish_r
 
Аватар для fish_r
Вьюер, контроллер, кто угодно (какой нибудь менеджер...), но не модель ) Модель не должны интересовать подробности отображения, она занимается данными и только. Иначе нарушается главный принцип MVC, сама суть - разделение данных, и отображения.
Старый 28.11.2011 16:15 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
А что по Вашему есть картинка? Для меня это 2 вещи: BitmapData и Bitmap. Первое - данные, которые я и предлагаю хранить в модели, второе - отображение, со своими rotation, scaleX/scaleY и прочими фильтрами.

Цитата:
Но в моделе не м.б. картинки, т.к. завтра картинка может поменяться
При таком раскладе модель диспатчит событие, отображение его ловит и обновляется.

Цитата:
какой нибудь менеджер...
Менеджер - это смесь из модели и контроллера, как правило.
Старый 28.11.2011 16:31 crazyone вне форума
crazyone
 
Аватар для crazyone
Ресурсы грузит менеджер ресурсов, который в схему включен точно так же, как коннектор и не является ни моделью, ни вьювером, ни контролером.
А кто посылает запрос на загрузку ресурсов - это уже другой вопрос. Смотря какой ресурс, смотря кому нужен. Если это ресурс вьюшки - вьюшка и просит, если ресурс модели - модель просит.
Старый 28.11.2011 16:50 fish_r вне форума
fish_r
 
Аватар для fish_r
Цитата:
А что по Вашему есть картинка? Для меня это 2 вещи: BitmapData и Bitmap. Первое - данные, которые я и предлагаю хранить в модели, второе - отображение, со своими rotation, scaleX/scaleY и прочими фильтрами.
Да, несмотря на то, что мы высказали противоположные мнения мы оба правы, всё зависит от контекста.
Является ли данное изображение частью данных приложения, если да, то оно интересует модель, если нет,
то нет.

Цитата:
Ресурсы грузит менеджер ресурсов, который в схему включен точно так же, как коннектор и не является ни моделью, ни вьювером, ни контролером.
А кто посылает запрос на загрузку ресурсов - это уже другой вопрос. Смотря какой ресурс, смотря кому нужен. Если это ресурс вьюшки - вьюшка и просит, если ресурс модели - модель просит.
Речь как раз и идет о том: кто инициализирует, передает и пр. Кто грузит, непосредственно то, понятно.
Старый 28.11.2011 17:11 fish_r вне форума
fish_r
 
Аватар для fish_r
Несмотря на то, что принципы MVC довольно ясно изложены на самом деле эту парадигму используют для двух разных целей, это:
- разделение программы на слабосвязанные компоненты,
- разделение отображения и логики.

ИМХО в первом случае MVC слабо эффективен, хотя может быть это выглядит парадоксально, эффективнее делить приложения на модули где смешана и логика и отображение. Попытка реализовать для этих целей MVC сильно усложняет архитектуру.

Зато во втором случае вряд ли можно придумать что то более эффективное. Как определить что является ресурсами вьюера, а что модели? Это просто. Представьте, что вы проектируете
программу которая будет работать и в условиях соц.сетей и как моб.приложение и как десктопное.Каждая из этих реализаций определяет свои требования к области и эл-там отображения. Так вот то что будет меняться в зависимости от реализации - это вьюер, а то, что не будет - это модель. Это грубо и при желании можно оспорить. Но, если подумать, то вполне понятно. А контроллер в любом случае лишь связующее звено интерпретирующее и контролирующее данные поступающие от вьюера.

Такое ИМХО ))
Старый 28.11.2011 17:13 crazyone вне форума
crazyone
 
Аватар для crazyone
Цитата:
Речь как раз и идет о том: кто инициализирует, передает и пр. Кто грузит, непосредственно то, понятно.
Всмысле? Инициализирует клиент или главный контролер, передается по дереву - запрос вверх, ответ - вниз.
Или я не понял вопроса.
Старый 28.11.2011 17:16 alatar вне форума
alatar
 
Аватар для alatar
Цитата:
Так вот то что будет меняться в зависимости от реализации - это вьюер, а то, что не будет - это модель.
View, в свою очередь, может сам реализовывать MVC.
Старый 28.11.2011 17:37 fish_r вне форума
fish_r
 
Аватар для fish_r
Цитата:
Всмысле? Инициализирует клиент или главный контролер, передается по дереву - запрос вверх, ответ - вниз.
Или я не понял вопроса.
Вопрос примерно так поставлен: должна ли быть вовлечена модель в события обновления вьюера? Должна ли она хранить и поставлять (и запрашивать) ресурсы необходимые для отображения?

Цитата:
View, в свою очередь, может сам реализовывать MVC.
Да, но это уже подробности. Я имею в ввиду то, что программа должна быть спроектирована так, что вне зависимости от особенностей отображения логика (и её часть отвечающая за логику) не должна как либо зависеть от конкретной реализации отображаемой, интерфейсной части.
Старый 28.11.2011 18:14 crazyone вне форума
crazyone
 
Аватар для crazyone
Цитата:
Вопрос примерно так поставлен: должна ли быть вовлечена модель в события обновления вьюера? Должна ли она хранить и поставлять (и запрашивать) ресурсы необходимые для отображения?
Ответ немного предсказуем:
Нет. Модель ничего ни о каком вьювере знать не должна.
Старый 28.11.2011 18:47 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Эмм... Событие модели никак не добавляет ей знаний о вьювере.

Цитата:
Должна ли она хранить и поставлять (и запрашивать)
Хранить - да, предоставлять доступ на чтение - да. Запрашивать - нет, в нее можно положить, из нее можно вынуть, но сама она просить ничего не должна. На то она и модель, собственно.

Кстати, что касается менеджера ресурсов - то, на мой взгляд, он должен состоять из двух элементов: 1) хранилища ресурсов (модель) и 2) загрузчика ресурсов (контроллер). А вьюверы уже получают из хранилища имеющиеся ресурсы или просят загрузчик что-то загрузить (если в хранилище нет того что им нужно) и подписываются на хранилище (которое в момент добавления ресурсов что-то диспатчит). Для меня такой подход оказался самым удобным и "чистым" с точки зрения понимания сторонних программистов (то есть тех, кто этот код получил как данность, а не как то, что нужно допиливать).
Старый 28.11.2011 19:22 СлаваRa вне форума
СлаваRa
 
Аватар для СлаваRa
+1 к тому что сказал gloomyBrain
Старый 28.11.2011 21:42 crazyone вне форума
crazyone
 
Аватар для crazyone
Я могу сказать и по другому. Модель должна быть одинаковой как для реализации с ГУИ, так и для консольного приложения.
Поэтому если это ресурсы модели - типа вот у нас в галерее такая вот картинка, то они очень даже должны быть в модели. А если это ресурсы вьюшки - типа вот так у нас выглядит кнопка, то в модели они не должны быть.

Реализация менеджера ресурсов как связка контроллера с моделью - это ваше личное дело. Решение хорошее, но модель менеджера - это модель менеджера и в общую модель она если и входит, то косвенно, так что о ней мы вобще не говорим.
Старый 29.11.2011 02:51 fish_r вне форума
fish_r
 
Аватар для fish_r
Цитата:
...но сама она просить ничего не должна. На то она и модель, собственно.
А это почему? Как это противоречит идее MVC? Может потому, что так сказали четверо "бандитов"? А они откуда знают? Лично с Йешуа разговаривали? ) Думаю, что нет.) Поэтому, ИМХО, модель может делать то, что хочет - запрашивать, отправлять, получать и пр. Единственное чего она не должна, если мы говорим о MVC, это быть завязанной на реализацию отображения интерфейса (интерфейсов). Ну и не быть в курсе подробностей структуры связи с data source, вроде как тоже хорошо).

Цитата:
предоставлять доступ на чтение - да
А на запись нельзя значит? Опять же почему? Да модели все равно кто меняет её данные. Надо вьюеру - пусть он меняет. Не суть. Просто вьюеру это делать, как правило, не с руки, ибо "один класс - одна задача", поэтому это сваливают контроллеру.
Старый 29.11.2011 12:27 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
@fish_r
Цитата:
Надо вьюеру - пусть он меняет. Не суть. Просто вьюеру это делать, как правило, не с руки, ибо "один класс - одна задача", поэтому это сваливают контроллеру.
Это уже MVVM, а не MVC. Доступ на чтение - всем, доступ на запись только своему контроллеру (если мы про MVC). Про компетенцию Gang Of Four я даже спорить не буду.

@crazyone
Цитата:
типа вот так у нас выглядит кнопка, то в модели они не должны быть.
Ну а где? Вот у нас есть 150 одинаковых тайлов. Где мы будем хранить отображение? В каждой вьюхе свое? - думаю, что нет. В менеджере ресурсов? Ну а чем он не модель? =)
Нет, я согласен, его можно назвать как угодно, но BitmapData, как меня ни убеждайте, для меня все равно останется данными, а не отображением. А то что хранит данные для меня останется моделью.

ЗЫ
Я вообще хотел сказать одну простую вещь: то ЧТО мы показываем - мы храним в модели. То КАК мы показываем - мы храним во View
Обновил(-а) gloomyBrain 29.11.2011 в 13:15
Старый 29.11.2011 13:15 incvizitor вне форума
incvizitor
 
Аватар для incvizitor
@gloomyBrain, Sprite тоже данные хранит x, y, width, height, а рендерит его фп. Sprite модель? Ресорс мэнеджер относят ко вьюхе, Так как при смене въюхи, данные его меняетсю. То есть привязан он привязан к конкретному отображению. При другом отображении может вообще не быть менеджера ресурсов, так как вместо кнопок приложение будет управляемо через микрофон. Так что если отделять логически данные приложения от его отображения - то ресорс менеджер должен быть связан с частью отображения.
Старый 29.11.2011 13:24 alatar вне форума
alatar
 
Аватар для alatar
Цитата:
Sprite тоже данные хранит x, y, width, height, а рендерит его фп. Sprite модель?
Да. Для рендерера плеера Sprite — модель. Все зависит от того, на каком уровне смотреть.
Старый 29.11.2011 13:47 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
@incvizitor
Ну мы о сферических конях в вакууме говорим, или о чем?
Вот есть flash-галерея. Она показывает картинки. Тут нам понадобилось поменять скин галереи.
Модель данных (а именно - те картинки, которые будем показывать) не меняется. Соответственно, в ресурс менеджер вносить изменения тоже нет нужды.
А вот View мы спокойно себе заменим. Ибо оно решает задачу "как показываем". И, да, x/y/rotation/filters - это все "как показываем", а не "что покаываем". Так что на уровне приложения (спасибо, alatar) Sprite как был View, так и остается.

А задачи управления решает контроллер - именно он знает, какую View ему слушать и что с этим делать (микрофон, клавиатура, джойстик, ...). И вряд ли у Вас возникнет задача сделать консольную галерею картинок =). Поэтому очевидно, что любая архитектура должна выполнять задачи данного приложения, а не для любого приложения.
Старый 29.11.2011 14:05 crazyone вне форума
crazyone
 
Аватар для crazyone
Цитата:
Ну а где? Вот у нас есть 150 одинаковых тайлов. Где мы будем хранить отображение? В каждой вьюхе свое? - думаю, что нет.
Каждая вьюха вольна считать, что у нее свое отображение. А в менеджере ресурсов оно не хранится, а кешируется.
Старый 29.11.2011 14:06 fish_r вне форума
fish_r
 
Аватар для fish_r
Цитата:
Это уже MVVM, а не MVC. Доступ на чтение - всем, доступ на запись только своему контроллеру (если мы про MVC).
MVVM - вариация на тему MVC. И в MVVM контроллер отсутствует, я же не сказал, что он не нужен или его не будет. И кто это сказал? Кто то на Вики? И теперь, если мне эффективнее что то сразу из вьюера
его собственной модели передать я из принципа буду огород городить?


Цитата:
Про компетенцию Gang Of Four я даже спорить не буду.
Это не про компетенцию, это про слепую веру.
Старый 29.11.2011 14:09 incvizitor вне форума
incvizitor
 
Аватар для incvizitor
2 случая:

1 - мы грузим картинки которые галерея отображает.
2 - мы грузим кнопки, индикаторы текущией картинки и т.д.

Я про картинки в галерее ничего и не говорил. Я говорил о кнопах. Вы хотите их в модели хранить?
Да, может это будет своего рода модель. Однако я до того и привел пример спрайта. битмападата это, как вы говорите модель, однако хранится она в той части приложения, которая отвечает за изображение. И это не будет, имхо, связано с основной моделью.
Старый 29.11.2011 14:14 fish_r вне форума
fish_r
 
Аватар для fish_r
Цитата:
А задачи управления решает контроллер
Ну почему?! Представьте: монитор, клавиатура, мышь - вьюер, кабеля и контроллеры - контроллер, системный блок - модель. С чего это провода решают что делать? Откуда это?
Старый 29.11.2011 14:15 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Цитата:
А в менеджере ресурсов оно не хранится, а кешируется.
Что-то я не в курсе разницы... Может, поясните? =)

Цитата:
Каждая вьюха вольна считать, что у нее свое отображение
Не согласен. Я вьюха и я хочу поменять свое отображение. Если я считаю, что оно принадлежит мне, то я спокойненько его заменяю (а так как оно лежит в модели и по сути одно на всех - то оно у всех возможных View и поменяется).
Коллапс.
Хотя по сути - это и есть ситуация, о которой говорит fish_r, когда View начинают менять данные. На мой взгляд это как раз и ломает всю концепцию MVC (о которой, кстати, fish_r и говорил =)) и данные начинают смешиваться с отображением.
Старый 29.11.2011 14:15 fish_r вне форума
fish_r
 
Аватар для fish_r
Цитата:
И вряд ли у Вас возникнет задача сделать консольную галерею картинок =)
Консольное приложение может запросто обрабатывать изображения, к примеру перекодировать...
Старый 29.11.2011 14:18 fish_r вне форума
fish_r
 
Аватар для fish_r
Цитата:
и данные начинают смешиваться с отображением
это частный случай, о котором выше сказал @alatar

Цитата:
View, в свою очередь, может сам реализовывать MVC.
Старый 29.11.2011 14:23 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Цитата:
Ну почему?! Представьте: монитор, клавиатура, мышь - вьюер, кабеля и контроллеры - контроллер, системный блок - модель. С чего это провода решают что делать? Откуда это?
Оттуда, что системный блок - контроллер, если проводить такие аналогии. Провода - система сигнлов.
Вы что-то печатаете (input во View). по проводам (система сигналов) ваши действия попадают в контроллер. Контроллер обдумывает ваши действия, и изменяет модель (текстовый файл). Модель сигнализирует об изменении и монитор (view) показывает результат ваших действий.
Старый 29.11.2011 14:36 fish_r вне форума
fish_r
 
Аватар для fish_r
Так к чему же относится "система сигналов"? К вьюеру, или к контроллеру? Что то из эти двух получается "два в одном".

Получается, что заменив монитор нам надо заменить системный блок?
Старый 29.11.2011 14:58 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Я считаю BitmapData данными, которые нужно сугубо вьюхе, посему не выношу их в модели триады.
Старый 29.11.2011 15:08 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Цитата:
Так к чему же относится "система сигналов"?
Ни к чему не относится.
Если говорить о программировании - то тут для разных интерфейсов ввода-вывода используются адаптеры и медиаторы.
В случае с системным блоком - это разъемы USB или PS/2.
И там, и там - это только транспорт и к MVC он имеет косвенное отношение.

В AS3 я использую события. Можно делать по системе сигнал-слот. Можно по-всякому.

Цитата:
Получается, что заменив монитор нам надо заменить системный блок?
Ну я вот не вижу в этом необходимости. И это Ваше изречение для меня непонятно.
Старый 29.11.2011 15:18 fish_r вне форума
fish_r
 
Аватар для fish_r
Цитата:
Ну я вот не вижу в этом необходимости. И это Ваше изречение для меня непонятно.
Это просто - только контроллер в курсе реализации вьюера, т.к. он интерпретирует его сигналы, а значит
с заменой вьюера нужно менять контроллер. А если в нём логика? То и логику менять? Что же останется?
Тупо - дата? Тогда зачем красивые слова "модель"? Назвали бы уже просто - "тупо - дата".
Старый 29.11.2011 15:22 incvizitor вне форума
incvizitor
 
Аватар для incvizitor
Цитата:
Это просто - только контроллер в курсе реализации вьюера, т.к. он интерпретирует его сигналы, а значит
с заменой вьюера нужно менять контроллер.
Контроллер в курсе интрефейса представления, точнее той его части, которая необходима для прослушивания событий.
Старый 29.11.2011 15:25 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Цитата:
только контроллер в курсе реализации вьюера, т.к. он интерпретирует его сигналы
Он в курсе сигналов, а не вьювера. И любой другой вьювер с такими же сигналами отлично подойдет.
Случай для системнго блока: мы можем поставить любой монитор с D-Sub разъемом, потому как в системном блоке у нас есть такое гнездо.
Случай для AS3: если View диспатчит какие-то события, то оно нам подходит.
Старый 29.11.2011 15:43 fish_r вне форума
fish_r
 
Аватар для fish_r
Цитата:
Контроллер в курсе интрефейса представления, точнее той его части, которая необходима для прослушивания событий.
Совершенно верно, и заметьте - конкретного интерфейса. А если мы меняем вьюер, то скорее всего изменится и интерфейс, и если раньше что то диспатчила кнопка, то теперь, вполне возможно этой кнопки вообще не будет, а данные будут изменяться в результате других событий. Затачивать вьюер
под контроллер? Контроллер под вьюер? А может ничего не надо ни под что затачивать?
Вроде суть идеи MVC как раз в том, что ни надо ничто ни под что затачивать, переделывать?
Старый 29.11.2011 16:11 incvizitor вне форума
incvizitor
 
Аватар для incvizitor
Код AS3:
package  {
	import flash.events.IEventDispatcher;
 
	/**
	 * ...
	 * @author vaukalak
	 */
 
	[Event(name="requestAction", type="flash.events.Event")]
 
	public interface IView extends IEventDispatcher{
 
	}
 
}
Объясните, какая контроллеру разница от чего въюшка диспатчнула "requestAction"?
Старый 29.11.2011 16:52 fish_r вне форума
fish_r
 
Аватар для fish_r
Да, в общем никакой, за исключением того, что вьюшка в данном случае выступает не только в качестве генератора сигнала, но также и его интерпретатора... Т.е. объясняет контроллеру то, что, по идее, он сам должен объяснять, вместо того чтобы заниматься сугубо своими делами... Если вы находите это нормальным... то, что я могу сказать... только то, что "ТуТуКовский" подход заставляет вас лезть все дальше
в какие-то непонятные, ненужные дебри.
Старый 29.11.2011 17:06 incvizitor вне форума
incvizitor
 
Аватар для incvizitor
Цитата:
в какие-то непонятные, ненужные дебри.
Код AS3:
private function _onClick(e:MouseEvent):void{
     dispatchEvent(new Event("requestAction"));
}
3 строчки кода. За то контроллер не зависим от представления (что и требуется). Въюшка оповещает контроллер о том что пользователь запросил действие, как он их запросил решает въюшка, контроллеру фиолетово. Он о въюшке вообще ничего не знает, кроме как то что у нее есть метод addEventListener а так же событие REQUEST_ACTION. За счет этого и достигается гибкость и предстваление становится независимым от логики и наоборот.
Старый 29.11.2011 17:34 fish_r вне форума
fish_r
 
Аватар для fish_r
Цитата:
3 строчки кода.
Которые должны быть в контроллере

Цитата:
За то контроллер не зависим от представления (что и требуется)
Требуется как раз обратное.

Ладно, я понял: вы переносите "центр тяжести" с модели на контроллер. На мой взгляд это не логично, т.к. понятия перестают отражать заложенный в них смысл.... Но в конце концов, мне дела нет... Я лишь
высказал своё мнение. Вы своё. Пусть каждый "останется при своих"...
 

 


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


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