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

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

Рейтинг: 5.00. Голосов: 3.

MVC, часть 2. Лирика и теория.

Запись от Psycho Tiger размещена 02.12.2010 в 17:58
Обновил(-а) Psycho Tiger 14.12.2010 в 18:11

Первая часть.

Жил был контроллер. Умный был... шибко умный. И хотел он чтобы его кто нибудь слушал... Хотел он холить и лелеять. И тут появилась она. Модель. Ничего лишнего, никаких порочных связей. Она была сама по себе, худа - из веса её кости, да обсервер - и красива - куда ни глянь, там аксессоры. Контроллер знал что делать.
Ловким движением он выцепил ссылку на модель и вонзил в себя. Теперь она его. Он вошел в неё и увидел много разных аксессоров к разным данным... Да, модель интересная личность.
Время летело незаметно. Не заметила модель, как появился в доме малыш вьювер, который беспрекословно слушал каждое слово своего папы и частенько думал о том, что стоит исполнять просьбы мамы. И был бы конец этой истории, но...
Контроллер всегда был единомышлеником. Он не знал как оправдаться перед своей моделью о непонятно откуда взявшейся вьюшке. Похоже, не одна модель у контроллера...

MVC, часть 2.
Итак, сразу скажу. Общепринятые понятия были даны в первой статье. Всё что здесь - является осколками моего разума по этой теме и кусочками того, что мне подсказали другие люди. Здесь нет правды, здесь нет лжи. Я так вижу моё MVC. Какое оно будет у вас - я не знаю.

Связь с внешним миром.

Здесь есть несколько вариантов. Все основаны на следующем: главный контроллер создаёт некий коннектор к серверу, который предоставляет данные, полученные с него, и имеет функционал который способен эти данные отправить.
Вариантов реализации - масса.
GoF паттерн Command: коннектор формирует команду и отправляет её контроллеру.
Что я имею ввиду: например, с сервера пришел xml
Код:
<response><action>chat</action><message>Hello!</message></response>
Создаётся некий экземпляр класса Command, содержащий в себе команду и действие.
Код AS3:
var c:Command=new Command();
c.action=xml.action.toString();
c.info=xml.message.toString();
Контроллер получив такую команду как-то её обрабатывает. Например, делает switch (c.action) и смотрит, что же конкретно хотели сказать.

Client: заводим в контроллере метод chat, а когда нам приходит команда от сервера - пример xml`ки сверху - делаем что-то вроде
Код AS3:
try{
_controller[xml.action.toString()].apply(this,xml.message.toString);
}
catch (error:Error){
trace("Method not founded");
}
т.е. вызываем динамическим доступом метод, имя которого пришло к нам с сервера.
Такое управление, кстати говоря, носит имя RPC.

Можно выдумать много разных вариантов как обрабатывать информацию с сервера - и все будут правильными. Далее я подробно опишу тот, который использую я.
Для начала заведем класс для работы с сервером. Сервера у нас нету, поэтому будем использовать следующий:
Код AS3:
package  
{
	import flash.utils.setTimeout;
 
	public class ServerConnector 
	{
		private var _controller:BaseController;
 
		public function ServerConnector(controller:BaseController) 
		{
			super();
			_controller = controller;
 
		}
 
 
		public function sendSomeCommand():void {
			setTimeout(randomCommand, 300);
		}
 
		private function randomCommand():void
		{
			var xml:XML =<xml/>;
			switch (Math.floor(Math.random() * 3)) {
				case 0:
					xml.action = "chat";
					xml.data = "Hello world!";
				break;
 
				case 1:
					xml.action = "add";
					xml.data = "monster";
				break;
 
				case 2:
					xml.action = "add";
					xml.data = "human";
				break;
 
				default: break;
			}
 
			_controller.onServerData(xml);
		}
 
	}
 
}
В чем суть - будем дёргать его единственный паблик метод, а он будет плеваться в контроллер случайной командой, которую мы будем обрабатывать.
Вот код главного контроллера:
Код AS3:
package  
{
	import flash.display.DisplayObjectContainer;
	import flash.events.MouseEvent;
 
	public class BaseController 
	{
		private var _host:DisplayObjectContainer;
		private var _connector:ServerConnector ;
 
		public function BaseController(host:DisplayObjectContainer) 
		{
			super();
			_host = host;
			_host.stage.addEventListener(MouseEvent.CLICK, onStageClick);
 
			_connector = new ServerConnector(this);
		}
 
		private function onStageClick(event:MouseEvent):void 
		{
			_connector.sendSomeCommand();
		}
 
		public function onServerData(xml:XML):void
		{
			var command:String = xml.action.toString();
			switch (command) {
				case "chat":
					trace("Chat message: " + xml.data.toString());
				break;
 
				case "add":
					switch (xml.data.toString()) {
						case "human":
							trace("Adding a human");
						break;
 
						case "monster":
							trace("Oh no, a monster!");
						break;
					}
 
				break;
			}
		}
 
	}
 
}
Что делаем: подписываемся на клик по сцене и как будто бы отсылаем серверу какие-то данные. А сервер нам как будто бы отвечает. После элементарно разбираем команду и выводим трейсом что-то там, в зависимости от того что нам пришло от сервера. В жизни мы можем приказать какому-то объекту что-то сделать, изменить модель и всё в этом духе. Свобода, эх. )
Но веселее становится если начать ветвить контроллеры. Эта вещь весьма спорная, но рассказать о ней стоит.

Ветвим контроллеры.

Зачем это нужно? Ну, например есть курилка, где можно найти себе соперника и есть основное поле боя. Очевидно, что между ними нет почти ничего общего, а значит, наверное, и логику было бы логично держать в разных контроллерах, верно?
Немного об их иерархии. Нижний контроллер может просить о чем - то верхнего, что понятно. Но может и... приказать! Например, выход из курилки в меню выбора персонажей - главный контроллер не может принять решение не удовлетворить такой переход. Переход обязан состояться, если контроллер курилки решит, что перейти нужно. Поэтому контроллеры общаются как событиями, так и напрямую.
Тут важно понять следующее: контроллер является дочерним, но это не значит что модель с которой этот контроллер работает тоже будет дочерней моделью. Дочерний контроллер может работать с любой моделью или с несколькими, даже только с главной моделью. Даже изменяя её. Если он её меняет - тогда дочернему контроллеру ставится статус "старшенького" сыночка по отношению к модели, которому можно. Бывают ситуации, когда контроллеру нужно считать что то с главной модели, но изменять её он право не имеет. Тогда он "младшенький". Ну это так, на пальцах. Порой и 140 кг гиганта бокса зовут малышкой, так что как кого называть - это ваше дело )
Не пугайтесь, если это показалось запутанным, это просто лирика.
Как реализовывать?
В главном контроллере когда нужно происходит нечто вроде
Код AS3:
var _smallController:SmallController = new SmallController(this, _view);
А в дочернем:
Код AS3:
package 
{
	import flash.display.DisplayObjectContainer;
	import flash.events.EventDispatcher;
	import flash.utils.setTimeout;
 
	public class SmallController extends EventDispatcher 
	{
		private var _baseController:BaseController;
		private var _view:DisplayObjectContainer;
 
		public function SmallController(baseController:BaseController, view:DisplayObjectContainer) 
		{
			super();
			_view = view;
			_baseController = baseController;
			setTimeout(_baseController.getOut, 200);
		}
 
	}
 
}
Дёрнув метод getOut нужно удалить младший контроллер из памяти. Для этого стоит завести в дочернем контроллере метод destroy, который подготовит контроллер к отходу в мир иной. Иногда он захватит с собой вью и модель. Иногда просто вью. Это зависит от нужд. Хотя, честно, не встречалось в моей практике случаев, когда удаляя контроллер не нужно было удалять вью.
Обычно дочерних контроллеров бывает несколько. Наверное, у вас появились такие мысли: наверное, разумно будет завести интерфейс ISmallController и реализовать его всем дочерним контроллером. В этом интерфейсе будет метод destroy. И интерфейс IBigController. В нём будет метод getOut и, возможно, get model. Потому что достаточно часто мелкому контроллеру нужно знать модель большого - в ней, например, хранится имя игрока.
Зачем? Всё очень просто. Зачем нужен большой интерфейс, я думаю, всем понятно - это инкапсуляция. С мелким интерфейсом интереснее: мелких контроллеров может быть много, и бывает так, что надо при их удалении просто дёрнуть метод destroy. Если сигнатуру метода getOut изменить вот так:
Код AS3:
getOut(controller:ISmallController):void
то можно один метод дёргать многими малышами.
Мысли, конечно, хорошие. Момент в том, что вы дёргаете метод, который дёрнет ваш метод. То есть вместо вызова getOut можно сразу вызвать destory, и эффект будет 1 в 1. Да и не бывает так, что контроллер удалился бесследно для других - в старшем контроллере надо что-нибудь да наколдовать. С подходом как есть сейчас, наверное, самым лучшим будет банальная проверка через is. А ещё лучше через switch:
Код AS3:
switch (controller){
case _smallController1: break;
case _verySmallController: break;
case _angelicaBoobsController: break;
}

Доставка сообщений в нужный контроллер.


Под сообщениями подразумеваются сообщения с сервера.
Если мы ветвим контроллеры - хотелось бы чтобы каждый контроллер мог пощупать сервер. Все щупки осуществляются через BaseController, у которого метод "отправить на сервер" помечен как public. А все дочерние контроллеры имеют к нему доступ. То есть мы просто дёргаем этот метод и говорим, что отправить. Всё просто.
Интереснее с доставкой сообщения от сервера клиенту. Давайте взглянем по логике: первым его получает ServerConnector (экземпляр класса, работающий с сервером), вторым его должен получить BaseController. Потом его младшие, потом младшие младших и так далее. Так и поступим. Ранее был рассмотрен пример получения сообщений от сервера, там был метод onServerData. Сообщение, собственно, попадает первым делом в этот метод. Главный контроллер парсит его и решает что делать. Он может в любом момент прекратить распространение сообщения, сделав return в методе. Он может в это сообщение написать матерное слово. Он как бы его хозяин.
В конце этого метода следует сделать dispatchEvent, а событие должно содержать сообщение от сервера. Все дочерние контроллеры имеют ссылку на базовый контроллер? Имеют. Они подписываются на событие отправки события у главного контроллера и выполняют какие-либо действия, если посчитают нужным. Более старшие контроллеры подписываются в коде раньше, чем более младшие, тем самым при одинаковых приоритетах прослушивания событий сообщение сперва попадёт в старший контроллер, а потом в младший. Как мы и планировали!
Но часто бывает так, что сообщение прошло через главный контроллер, но ему на это сообщение наплевать. Например, это сообщение чата. А сообщение чата очень хочет получить контроллер чата. С методом выше, конечно, всё получится. Но давайте представим, что контроллер чата вдруг умер. Отвалился. Сгорел. Значит сообщение чата будет существовать, но обработки не получит. Другими словами, это сообщение мы вдруг проворонили. И кто виноват? А сообщение пришло с сервера? А нижний контроллер его поймал? А может случилось так, что всё прошло хорошо, но это сообщение просто не вывелось на экран?
Столько вопросов... Знакомая ситуация? Её серьезно облегчает MVC.
Вы знаете, что есть у объекта Event такое свойство как cancelable? Слыхали, наверно. В общем, в 2 словах - наверняка вы замечали, что делая dispatchEvent этот самый метод возвращает какое-то там булево значение. Ах да, удалось ли событие отправить или нет. Не задумывались - как это так, удалось ли отправить событие? Возможно, конечно, тут вольности моего перевода. Но смысл такой - был ли вызван preventDefault для этого события. А вызвать его можно только в обработчиках. Другими словами:
Код AS3:
trace( dispatchEvent(event) );
 
private function handler(event:Event):void{
event.preventDefault();
}
trace покажет false. Однако если убрать строчку с preventDefault, то trace покажет true. Но preventDefault работает только если событие было создано с флагом cancelable.
К чему я клоню? А вот к чему. Если событие вдруг нашло адресата в лице младшего контроллера - событию зовётся preventDefault.
Вот так рассылаем событие всем желающим:
Код AS3:
if (super.dispatchEvent(event)) log("Api:unknown command:" + command);
Например вот так написан код у желающих (внутри обработчика события)
Код AS3:
switch (command) 
{
	case "getFriendsInfo":
	...
	break
 
	case "questGetInvite":
	...
	break;		
 
	default: return;
}
event.preventDefault();
Таким образом если команда нашла адресата в этом контроллере - тогда вызовется event.preventDefault(). А если не найдется - сработает return, и preventDefault() не вызовется. Тем самым мы добавили автоматики - работаем, не включая голову - а о "лишней" команде нас любезно предупредят. Ляпота.

Мысли о ветвлении моделей.
Слышали о GoF Composite? DisplayList во флеше реализует именно его. Реализация заключается в том, что одних детей можно вкладывать в другие. У нас - методом addChild(At). Чем прелестно? Тем, что наблюдается строгая иерархия. Зачем это надо? Например, есть у вас модель дома. В доме - квартира. В квартира - шкаф. В шкафу - надувная женщина. Матрешка, в общем. Но пока главный герой ходил в театр его дом взорвали. Совсем взорвали. Модель дома должна удалится. А вместе с тем должны удалится квартиры в нём, шкафы... ну и элементы личной жизни. Стрёмной, но личной.
Вообще такая иерархия реализуется обычными полями класса. Если в модели House завести поле Cabinet, а в нём Woman - то удаляя House удалятся и его поля, по сути говоря. То есть то, что мы и хотели. Но такое ветвление моделей... не очень. Женщина всего одна в шкафу. И делая дом Казановы - надо бы трёх женщин в дом, пятерых в шкаф. А у Моисеева и не женщин вовсе.
И вот сталкиваемся с проблемкой - казалось бы, модели похожие. Все дома имеют количество этажей и объем, к примеру. А с другой стороны - дома разных людей отличаются наполнением.
Нет, можно конечно создавать массив Women, давая неограниченное количество женщин в дом (не истекайте слюной, по сюжету они резиновые), но ведь не предусмотришь всего-всего. Наверное, можно завести один большой массив. Нетипизированный. И туда пихать всё что хотим! Отличная идея. Теперь в домах есть всё что угодно, неплохо. Причем где-то объект может содержать в себе ещё что-то (Cabinet), а что-то не может (Woman. Нет-нет, вы можете запихать в неё что-нибудь, мы не о том). Было бы здорово разделять одиночную модель и композитную. В которую нельзя класть и в которую можно...
И вот мудрим-мудрим-мудрим и приходим к тому, что идеально это всё реализовано в дисплай листе. Однако я считаю это плохим тоном - использовать в качестве моделей DisplayObject. Расходы памяти больше, по автокомплиту много чуши... да и ощущение кривизны накатывает )
Лучше реализовывать такой самостоятельно. Но есть у DisplayObject`ов плюс - event bubbling. Это 2 параметр в конструкторе Event, если кто не понял. Можно отправить событие бабблясь... Зачем такое может пригодится?
Например, есть у вас игра клёвая. В игре периодически появляются здания, на здании появляются пушки и вертолеты и всякое такое. И иногда это неудобно - создавать модель, потом создавать вьюшку, кормить вьюшку моделью. Куда удобней было бы просто создать модель и сказать ей - "сядь на крышу здания"
Код AS3:
building.addChild(helicopter);
А вьюшка сама взяла бы - и подцепилась к вьюшке здания. Создали нового солдата - его вьюшка подцепилась к вьюшке заднего двора, где они респаются. Фантастика?
Да нет же. Как только модель добавляется - т.е. вызывается addChild в любой модели - должно диспатчиться событие Event.ADDED. Оно бабблится до самой главной модели игры. И где то там его ловит главная вьюшка. Она спрашивает у модели - что приключилось? А модель ей - мне поступили сведения что новая модель присоединилась ко мне! И вьюшка цепляет новую вьюшку. Туда куда надо. Повторяя иерархию прям в моделях. Вот и бабблинг пригодился.
Конечно, можно делать оптимизации. Например, бабблинг необязателен: модель говорит о том, что в неё кого-то добавили. И вьюшка этой модели сразу добавляет нужную вьюшку. Я просто хотел показать вам, что бабблинг в моделях иногда нужен. Например, в контексте этой задачи для подсчета прицепленных моделей. Нотификация "пересчитай сколько у тебя моделей" или "я присоединился и присоединил с собой 3 модели!" отправляется наверх именно бабблищимся событием.

Нависает вопрос. Как же реализовать бабблинг, не пользуясь DisplayObject`ами? Есть у меня несколько идей. И у вас должны быть.

На этом я закругляюсь. Информации здесь я изложил даже более, чем обычно использую на практике. MVC у каждого свой, не бойтесь экспериментировать. Изложенная выше теория - набор моих мыслей, которые я более-менее использую на практике. Они служат пищей, но если вы придумали, например, новый способ доставки сообщений по контроллерам - не стесняйтесь его использовать. Делайте как вам удобно. MVC создан помогать, а не угнетать.
Кстати, взгляните на картинку:
http://www.flasher.ru/forum/showpost...54&postcount=2
Она всё ещё вызывает у вас страх и ужас?

От автора:
Если соберусь с силами - напишу 3 часть. Часть будет целиком состоять из примера с объяснением - как же реально работает большой проект на MVC. Но думать что в ней всё прояснится ненужно - в неё не будет ничего нового. Только скомпонованные знания из первой и второй "в реальной битве".
Всего комментариев 37

Комментарии

Старый 03.12.2010 00:12 Котяра вне форума
Котяра
 
Аватар для Котяра
Ох. Ну вот не люблю я кэйсы.. Для Messages и Actions лучше всё-же стратегия наверное..
Код AS3:
public function onServerData(xml:XML):void
{
// создаём команду нужного класса (наследника BaseCommand ) и заполняем поля
var command:BaseCommand = BaseCommand.serializeFromXML(xml);
// выполняем действие над моделью.
command.execute(this /* контроллер*/, model/*Model*/);
}
Цимус в том что может быть много разных методов сериалицации XML/JSON/AMF/ProtoBuf
Экшены можно повторно использовать ( с определёнными условиями конечно)
и нет чёртовых кэйсов)
Обновил(-а) Котяра 03.12.2010 в 00:20
Старый 03.12.2010 00:17 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
В таком случае придется под каждую команду делать отдельный метод. Не всегда действие должно затронуть модель...
Первое - если не нужно RPC - по мне делать не очень. А идентификатор команд всё равно будет.

Короче, мне switch удобней.)
P.S. я клёвый!
Старый 03.12.2010 00:19 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Даешь часть 3! =) Отличная статья, читал и получал удовольствие. Правда с женщинами во множественном и единственном числе есть проблемы (в плане написания)
Старый 03.12.2010 00:25 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Спасибо.
Покажи пожалуйста где. Можно в личку/аську)
Старый 03.12.2010 00:29 Котяра вне форума
Котяра
 
Аватар для Котяра
Цитата:
В таком случае придется под каждую команду делать отдельный метод. Не всегда действие должно затронуть модель...
не понял немножко: что значит отдельный метод? есть один общий метод на всех
execute - для каждого класса он свой.
пример
вместо
Код AS3:
case "chat":
					trace("Chat message: " + xml.data.toString());
				break;
Код AS3:
public class ChatMessage extends BaseMessage
{     
      // заполняется при сериализации
      public var data:String;
 
      override public function execute(controller:Controller, model:Model)
      {
	      trace("Chat message: " + xml.data.toString());
             //  а в реале меняем модель
            model.addChatData(data);
 
       }
}
ничего другого по-хорошему экшену знать не надо, а если и надо у него есть полный доступ к контроллеру
Код AS3:
controller.mainView.kickAss();
Старый 03.12.2010 00:34 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Не о том подумал.
А мне приходит под 40 команд для одного контроллера и одной модели. Что мне делать при твоём подходе?

P.S. это и есть то, о чем я говорил в статье, дорогие читатели, решившие прочитать ещё и комментарии. MVC - у каждого свой.)
Старый 03.12.2010 00:38 Котяра вне форума
Котяра
 
Аватар для Котяра
а регистрацию классов
хорошо делать с помощью
registrerClassAlias("chat", ChatMessage);
либо просто заносить в хэш какой-нибудь
а потом в классе BaseCommand
Код AS3:
 public static function serializeFromXML(xml:XML):BaseCommand
{
var classRef:Class = getClassByAlias(xml.action);
var command = new ClassRef();
//парсим данные
command.getDateFromXML(xml);
return command;
}
Старый 03.12.2010 00:40 Котяра вне форума
Котяра
 
Аватар для Котяра
Цитата:
А мне приходит под 40 команд для одного контроллера и одной модели
40 классов сообщений.
кэйс из 40 элементов - это намного хуже.

При добавлении 41-го сообщения:
  • создаём ещё один класс сообщения.
  • описываем способ сериализации(для AMF и PB почти автоматом).
  • описываем метод execute.
  • регистрируем алиас.
  • остальные классы не трогаем.
зеркально можно также поступать на сервере.


И MVC тут вроде не причём вообще. Стратегия применима и к другим архитектурам.
Обновил(-а) Котяра 06.12.2010 в 02:31
Старый 03.12.2010 11:50 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Ну как бы да, непричем. Но это важно чтобы люди думали и везде выбирали то, что нужно именно им.
Мы сейчас амф используем в проекте, только вот от алиасов отказались, передавая просто хэш. Как раз из за мысли, что 80 классов ради команд заводить - это !@#$!#.
Старый 03.12.2010 13:50 Котяра вне форума
Котяра
 
Аватар для Котяра
Ну хозяин барин. По мне - 80 классов завести самое то.
они очень хорошо выглядят в папке project.
захотел - исправил метод execute в классе GalaktekoOpasnosteMessage
чем искать какието кэйсы и свичи.
Обновил(-а) Котяра 06.12.2010 в 02:35
Старый 04.12.2010 14:42 terbooter вне форума
terbooter
Я тоже использую AMF формат для общения с сервером (Zend AMF и Red5) Маппинг работает нормально. Для мелких проектов маппинг использовать не рационально. Мелкий, это 10-30 команд
Старый 04.12.2010 15:54 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Имо нет понятия "Нерационально". Как сказали мне однажды Димарик - это бред, что MVC не для маленьких проектов. То же и с AMF - если делать так всегда - то так всегда. Если не всегда - то не всегда.
А мы рельсы гоняем)
Старый 07.12.2010 08:51 terbooter вне форума
terbooter
Бред - это отрицать параметр рациональности как характеристику технической задачи.
Программирование, это больше математика, чем фигурное катание. Поэтому для определенного контекста всегда можно сказать, что рационально, а что не очень =)
Старый 07.12.2010 14:23 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Я не отрицаю рациональность. Я говорю что нет понятия "нерационально". Более рационально, менее рационально - есть. Конечная инстанция в виде "нерационально" - нету.
Старый 13.12.2010 01:01 formid вне форума
formid
Опять отличная статья) после того как ее прочитал решил немного переделать свой проект и случайно заметил что количество классов увеличилось вдвое,а суммарный код во столько же раз уменьшился. Вобщем влияние от статьи позитивное)
Старый 13.12.2010 01:24 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Кстати говоря, я тоже не стою на месте и некоторые моменты описанные мной в статьях иногда мне кажутся не столь хорошими. Как яркий пример - прошло всего ничего времени, а я тотально переосмыслил подход к клиент-серверу и вариант Котяры мне уже нравится куда больше моих кейсов.
Старый 12.10.2011 16:46 Sozonov вне форума
Sozonov
Огромное спасибо за обе статьи по MVC!
Планируешь ли ты обещанную третью часть?
Старый 30.11.2011 12:17 dsQuadro вне форума
dsQuadro
 
Аватар для dsQuadro
Прочитал обе статьи, очень понравились! Спасибо! все стало гораздо яснее(и даже схема etc...)... но возник вопрос:
к примеру: есть консоль админстратора для управления галереей... в ней создаются разделы, комментируются картинки и тд... предположим это сделано по принципу MVC... но есть еще модуль редактирования картинок после загрузки(который в свою очередь тоже хочется сделать MVC и чтобы его можно было гдето еще использовать)... от сюда возникает вопрос: этот одель редактора, чтобы соблюсти архитектуру MVC, надо раздербанить на 3 составляющие, и каждую составляющую сделать наследником соответственно M, V и C... но это сильно усложнит архитектуру всего приложения... а еслиже его оставлять отдельным, цельным, модулем то куда его пихать??? в контроллер?(ведь он тоже будет думать и обрабатывать... и выдавать важный результат для всего приложения) или же всетаки во вьюшку, ведь это видимый модуль, и его можно рассматривать как визуальный компонент??? надеюсь не очень сумбурно...
Старый 01.12.2011 19:40 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
@Sozonov, со временем балда огромная. Как нибудь, когда напьюсь. )

@dsQuadro, сумбурно, и я мало чего понял )
Прелесть в том, что вся триада реализуется "как хочется". Например, вью может быть тоже MVC, причем главное MVC, которое и содержит это вью ничего не знает о том - MVC оно или что-то другое. Когда внутри MVC компоненты тоже MVC - это нормально и порой даже хорошо.
Старый 13.01.2012 10:50 carrotoff вне форума
carrotoff
 
Аватар для carrotoff
Цитата:
Сообщение от Psycho Tiger
Нависает вопрос. Как же реализовать бабблинг, не пользуясь DisplayObject`ами? Есть у меня несколько идей. И у вас должны быть.
Переделываю проект на новый лад, ощутил прелесть композиции модели. Хочется всё-таки выяснить более конкретно по этому поводу.

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

Но что-то мне подсказывает, что это как-то печально. Поделитесь мыслями и опытом, пожалуйста.
Старый 13.01.2012 11:52 СлаваRa вне форума
СлаваRa
 
Аватар для СлаваRa
Цитата:
Переделываю проект на новый лад, ощутил прелесть композиции модели. Хочется всё-таки выяснить более конкретно по этому поводу.

Мне пока в голову приходит только следующий способ: создать классы одиночной модели и модели-контейнера.
У меня так (надеюсь, я прав, что как на скрине от etc, искать ссылку некогда, на форму в статье по MVC):
примерно
Model: AnyDataItem -> DataContainer -> Data -> EventDispatcher -> ...
View: AnyViewItem -> DisplayObjectContainer -> DisplayObject -> ...

Data - при изменении парента, по идее может (хотя может быть должна) диспатчить Added\Removed, но у меня такой необходимости, пока, не было.

я знаю, что у Вlooddy есть реализация:
Цитата:
Нависает вопрос. Как же реализовать бабблинг, не пользуясь DisplayObject`ами?
Обновил(-а) СлаваRa 13.01.2012 в 12:50
Старый 13.01.2012 12:48 carrotoff вне форума
carrotoff
 
Аватар для carrotoff
Да, схема известная. В теории вполне понятно. Пытаюсь на практике реализовать
Старый 13.01.2012 13:02 СлаваRa вне форума
СлаваRa
 
Аватар для СлаваRa
немного отредактировал свой пред. пост.
Цитата:
Да, схема известная. В теории вполне понятно. Пытаюсь на практике реализовать
на практике, DataContainer -> имеет практически все те же методы что и DisplayObjectContainer, Data имеет read свойство parent

Например. у меня персонаж выглядит так

Модель:
CharacterData -> CharacterDataItem -> DataContainer -> Data
CharacterData - получает данные для формирования структуры всего персонажа.
CharacterDataItem - каждая отдельная часть (будь то весь персонаж, или палец кисти правой руки).

данные для формирования структуры - XML - "выглядит" также

Вью:
CharacterView === CharacterData в плане того, что состоит из CharacterViewItem (является родителем\контейнером).

CharacterView - слушает\отображает CharacterData.
CharacterViewItem - слушает\отображает CharacterDataItem.

пс.
я не знаю как понятнее выразиться, но надеюсь, есть смысл и толк от того, что я написал.
Старый 13.01.2012 13:18 carrotoff вне форума
carrotoff
 
Аватар для carrotoff
Фишка в зеркальности данных, понятно.
Старый 13.01.2012 13:20 СлаваRa вне форума
СлаваRa
 
Аватар для СлаваRa
Да, это очень сильно упрощает и ускоряет разработку.
Старый 13.01.2012 14:15 Котяра вне форума
Котяра
 
Аватар для Котяра
Старый 13.01.2012 14:45 carrotoff вне форума
carrotoff
 
Аватар для carrotoff
Цитата:
Спасибо. Это очень интересно
Старый 13.01.2012 15:00 СлаваRa вне форума
СлаваRa
 
Аватар для СлаваRa
И проверь ЛС, если еще не видел нового сообщения
Старый 14.01.2012 21:20 fish_r вне форума
fish_r
 
Аватар для fish_r
Цитата:
Спасибо BlooDHounD! Спасибо Котяра!

Просто гениально! Гениально просто! Короче, лошадиный восторг!)
Старый 25.06.2012 17:54 tsarapkabel вне форума
tsarapkabel
 
Аватар для tsarapkabel
Интересненько Psycho Tiger придумал с
Код AS3:
event.preventDefault()
буду использовать!
Старый 25.06.2012 23:19 dimarik вне форума
dimarik
 
Аватар для dimarik
Кстате, про AMF. Десериализация типизированного AMF создает объекты в два раза шустрее, чем это можно сделать байткодом. Чем больше полей у объекта, тем существеннее разница. Если у вас внутре гоняется много объектов, то можно попробовать создать один в рамках ByteArray и глупо его размножить в тех же рамках. Затем
Код AS3:
registerClassAlias('1', SomeClass); 
const arrayOfSomeClassObject:Array = amf.readObject();
Старый 26.06.2012 09:58 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Цитата:
Интересненько Psycho Tiger придумал с
Это идея dimarik'а, к слову.
Старый 26.06.2012 20:34 dimarik вне форума
dimarik
 
Аватар для dimarik
Та я-то не сам придумал. Все было до нас. Это GoF chain of responsibility
Старый 04.02.2013 21:22 tsarapkabel вне форума
tsarapkabel
 
Аватар для tsarapkabel
Вопрос по ветвлению view: как правильней?
1. BaseController создаёт BaseView, которая, в свою очередь, создаёт несколько дочерних MiniView. Тогда при некой интерактивности пользователя в дочерней MiniView испускается событие. Его ловит BaseView и передаёт BaseController'у.
2. BaseController создаёт MiniController'ы, которые, в свою очередь, создают MiniView. Получится что-то вроде медиаторов. При взаимодействии пользователя с MiniView, MiniController будет ловить от него событие и передавать в BaseController.

И ещё вопрос: контроллер создаёт View, в котором есть другое MiniView. Как в контроллере ловить события от MiniView напрямую? Т.е. как получить ссылку в контроллер, если базовый класс MiniView заранее неизвестен?
Старый 04.02.2013 23:28 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Цитата:
Тогда при некой интерактивности пользователя в дочерней MiniView испускается событие. Его ловит BaseView и передаёт BaseController'у.
А зачем BaseView его ловить? Оно всплывет до самого корня, через BaseView. Контроллер может его сразу ловить. Иногда, конечно, требуется процессинг этого события через BaseView, например, поймали "частное", отдиспатчили "общее", так что по ситуации.

Оба варианта – и 1, и 2 – нормальные.
Хотя мне, если честно, в 70% разработки хватает Delegate Model. Это когда контроллера нет.

Цитата:
И ещё вопрос: контроллер создаёт View, в котором есть другое MiniView. Как в контроллере ловить события от MiniView напрямую? Т.е. как получить ссылку в контроллер, если базовый класс MiniView заранее неизвестен?
Бабблингом. У контроллера в один момент времени должна быть одна вью. Эта вью может менятся и в принципе контроллер не волнует, с чем именно он работает. Называется "вью" – и шикарно, он не должен заметить подставы, если GUI-приложение перешло в консольное – как работал, так и работает.
Так вот, я о чем: если контроллер рулит сразу двумя вью – скорее всего, Вы делаете что-то неправильно. У вью может быть множество других вью внутри (партиалов ?), даже другие МВЦ триады, и триады в триадах. Прелесть как раз в том, что происходит дележка. Контроллер работает с моделью (моделями), записывая туда что-то и одной вью, которую он слушает. Как запись происходит в моделях, как устроены вью – всё скрыто пеленой и мраком.
Старый 05.02.2013 17:23 tsarapkabel вне форума
tsarapkabel
 
Аватар для tsarapkabel
С бабблингом понял, спасибо.

Цитата:
Это когда контроллера нет.
Вью сам меняет модель и слушает её события для своего рендеринга?

Цитата:
У вью может быть множество других вью внутри, даже другие МВЦ триады...
Главное вью управляет кучей дочерних вью. Таким образом, для отображения какого-то дочернего вью, понадобится в главном вью создать мини-контроллер, который уже инициализирует это самое дочернее вью и, при необходимости, его модель?
Старый 06.02.2013 16:33 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Цитата:
Главное вью управляет кучей дочерних вью. Таким образом, для отображения какого-то дочернего вью, понадобится в главном вью создать мини-контроллер, который уже инициализирует это самое дочернее вью и, при необходимости, его модель?
Да. Ну, как пример: мультиплеер игра с сервером. Контроллер – это сервер, Модель - это база данных, а Вью - это клиент. Сам вью делится на свою триаду – тоже MVC. У Вью есть свои приблуды, которые можно расщепить ещё на триаду. Голова плохо варит, но иногда бывает удобно.

Цитата:
Вью сам меняет модель и слушает её события для своего рендеринга?
Ну не настолько маразматично, что поменял модель-словил событие, но как-то так. Часто контроллер является слишком тонким, служа только для развяки модели от вью. Настолько тонким, что можно часть функциональности впихнуть в модель, остальное – во вью.
 

 


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


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