PDA

Просмотр полной версии : Хорошее MVC


Страницы : [1] 2 3

Psycho Tiger
05.04.2010, 18:00
UPD: Прошло больше, чем полгода. Много воды утекло, многое осмыслили и многое поняли.
Если Вы зашли сюда почитать об MVC, не зная что это или не зная, как его применять в простейших случаях, то на правах саморекламы рекомендую почитать мои статьи об MVC.
Часть первая. (http://flasher.ru/forum/blog.php?b=256)
Часть вторая. (http://flasher.ru/forum/blog.php?b=262)
В основном они содержат мысли из этой темы и всего остального, что в то время мне удалось найти про "ручной" MVC.

Оригинальное сообщение:
Раньше делал жалкие подобия (хотя сложно назвать и подобиями) - например, вьюшка создает модель, то есть совсем всё плохо - теперь хочу начать делать грамотно. Наслушавшись etc про то, что PureMVC гавно и wxvxw про то что MVC вообще не может быть фреймворком (с последним согласен полностью - не понимаю, как архитектуру можно обернуть в универсальный фреймворк) встаёт вопрос - а как сделать правильное MVC? Гугл внятного ответа не дал, лишь что модель хранит и обрабатывает все данные, вьюшка отображает, а контроллер связывает эти 2 штуки.
Собственно, помимо просьбы дать статьи на правильный MVC ещё прошу объяснить вот какие моменты:
1) Кто кого создаёт? (для простоты будем отправной точкой брать базовый класс) - базовый класс создаёт контроллер, который создаёт вьюшку и модель, или как вообще? (может написал глупость, просто совершенно не понимаю кто кого - лишь для наглядности примера, что я хочу узнать)

2) У кого должны быть на кого ссылки и у кого не должны быть?

3) Понимаю, что главная сцена - это одна большая вьюшка, а в ней другие вьюшки от других моделей и т.д. Но вот эти "внутренние" MVC, откуда у них ноги растут? Или базовый класс, в который всё добавляется не должен быть построен по структуре MVC? Опять могу говорить глупости, вопрос может быть тупо из за непонимания механизма.

4) M+VC, VM+C - в чем разница?

5) В случае появления базы данных, кто с ней работает и кто имеет на неё ссылки?

Вообще в идеале было бы здорово какой нибудь элементарный пример, например таскание мячика. Где то видел блог про "хорошее" MVC тут на флешере, но найти не смог :(
Спасибо, что прочитали до конца, буду рад любой помощи.

fljot
05.04.2010, 18:10
хз)

Новая хрень появилась — RobotLegs зовётся, попробуй подёргать её за всякое.

http://www.robotlegs.org/
http://shaun.boyblack.co.za/blog/2009/04/29/another-architectural-framework-but-why/

etc
05.04.2010, 20:04
1) Контроллер создает и модель и вьюшку;
2) http://www.flasher.ru/forum/showpost.php?p=860254&postcount=2
3) Рутовый класс создает рутовый же контроллер и передаёт ссылку на самого себя как на контейнер вьюшек. Всё;
4) M+VC — контроллер интегрирован во вьювер. В общем-то, это контрол. VM+C — вьювер с интегрированной моделью. В принципе это ItemRenderer, по идее;
5) Отображает вьювер, изменяет контроллер. И у того и другого есть ссылки на базу.

Psycho Tiger
05.04.2010, 20:28
1) Так, хорошо. А если вьюшку создаёт он сам, то как её добавить? Диспатчить кастомное событие?

2) Да, медитировал на схему ещё давно, однако она мне кажется слишком сложной и поспешной для выводов, но я попробую сформулировать постулаты, и чтобы не утруждать вас лишней писаниной буду рад просто плюсикам над правильными высказываниями:
а) Самый главный контроллер создаёт ещё кучи контроллеров
б) Контроллер так как создал модель имеет ссылкой и вьюшку, и модель
в) Вьюшки порождают вьюшки... А кто их контроллер и где их модель?

Дальше, если представить что Data=модель
г) view events - событие о том, что вьюшку нужно обновить? Обычное бабблинг событие? Но ведь бабблинг событие ~31 раз в секунду достаточно ресурсоемко - как же быть?

4) это мне понятно, мне не понятно с точки зрения реализации. M+VC - связь с моделью напрямую из вьюшки так? А каокй толк в VM+C?

И появился новый вопрос - а где происходит вся логика? В Модели? То есть модель - эта вся логика, а контроллер призван помочь вьюшке отобразить это, верно?

etc
05.04.2010, 21:33
1) Добавить куда? Есть ссылка на контейнер для вьюшек;
2)
а) Не всегда, младшие контроллеры могут ещё более младших создавать;
б) Не понял;
в) Снаружи, на них ссылаются. Вьюшке максимум отдается ссылка на модель-контейнер;
г) Нет, view events — события от вьювера. Например MouseEvent.CLICK. А какая связь между ENTER_FRAME и бабблингом, я не уловил;
4) Модель обычно не имеет ссылок ни на вьюшек, ни на контроллеры, она сама по себе. Равно как она и не содержит логики, логика находится в контроллера. Задача модели — хранить данные и уведомлять об изменении.

Psycho Tiger
05.04.2010, 22:07
Спасибо, начинаю понимать.
1) Я так понимаю в контроллер всегда передаётся DisplayObjectContainer, говорящий куда пихнуть вьюшку?
б) я имею ввиду что раз контроллер создаёт и вьюшку, и модель то он сохраняет их ссылки. Ну в принципе вопрос риторический, не сохранять было бы глупо.
в) а как можно ссылаться снаружи на то, что было создано внутри? Диспатчится событие и на неё начинают ссылаться?
г) теперь понял что это, думал о другом =)

Такс, применив свои знания набросал это в коде, посмотри пожалуйста:
Базовый класс:
package
{
import flash.display.Sprite;

public class JustMain extends Sprite
{

public function JustMain()
{
super();
var controller:Controller = new Controller(this);
}

}

}

Контроллер:
package
{
import flash.display.DisplayObjectContainer;
import flash.events.Event;
import flash.events.MouseEvent;

public class Controller
{
private var _model:Model = new Model();
private var _viewer:Viewer = new Viewer();
private var _container:DisplayObjectContainer;
public function Controller(container:DisplayObjectContainer)
{
_container = container;
init();
}

private function init():void
{
_container.addChild(_viewer);
_model.addEventListener(Event.CHANGE, onModelChange);
_viewer.addEventListener(MouseEvent.CLICK, onViewerClick);

}

private function onViewerClick(e:MouseEvent):void
{
_model.change(Math.random() * 400, Math.random() * 400);
}

private function onModelChange(e:Event):void
{
_viewer.updatePositions(_model.x, _model.y);
}

}

}

Моделька:
package
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;

public class Model extends EventDispatcher
{

//no getters/setters, just example
public var x:Number = 0;
public var y:Number = 0;

public function Model()
{
super(null);

}

public function change(x:Number, y:Number):void {
this.x = x;
this.y = y;
super.dispatchEvent(new Event(Event.CHANGE));
}

}

}

И вьюшка:
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;

public class Viewer extends Sprite
{

public function Viewer()
{
super();
init();
}

private function init():void
{
var someSprite:Sprite = new Sprite();
someSprite.graphics.beginFill(0);
someSprite.graphics.drawCircle(0, 0, 50);
someSprite.graphics.endFill();
super.addChild(someSprite);
someSprite.addEventListener(MouseEvent.CLICK, super.dispatchEvent);
}


public function updatePositions(x:Number,y:Number):void {
this.x = x;
this.y = y;
}
}

}

По клику на кружок событие идёт в контроллер, оттуда просит модель изменить данные, модель данные меняет и говорит контроллеру, который обновляет вьюшку.

Возникает отсюда уже несколько вопросов:
1) Чтобы было совсем идеально-правильное MVC на твой взгляд, что нужно добавить, а что убрать?
2) Наверное, на столь простом примере не видно - но зачем такой полёт данных? Ведь если контроллер изменяет все данные, а моделька их всего лишь хранит - тогда, наверное, контроллеру уж точно видно что данные изменены и надо что то сказать вьюшке, зачем в моделе уведомлять об изменении?
3) А если я ф-цию change заменю 2-мя сеттерами, тогда я дважды вызову уведомление об обновлении, что плохо. Как быть?

Было бы очень здорово, если бы ты ткнул на конкретно этом примере, как сделать лучше.

dimarik
05.04.2010, 22:43
Сильно не читал =) Схема от Дениса и Николая стоит у меня как обои на домашнем компе ).
Кто кого создает. Для нас самое важное - создание структуры MVC в рантайме. Кем это будет сделано - совершенно не важно. Важно, что вся тройка будет создана (инстанцированы все три составляющие). Сделайте DocumentClass как фабрику конкретной структуры MVC по какому-либо конфигу. И забудьте о том кто кого инстанцирует вначале. Просто вначале есть эта тройка. Теперь Модель под властью Контроллера. Он ее холит и леет. Именно он интерпретирует порой кривые данные от сервера. Именно он добавляет логику в наши "тонкие" клиенты, когда серверные разрабы пожимают плечами и разводят руки, мол, не можем, ибо хайлоад. Ну а вьюха, она и в африке вьюха. Красивое, но тупое создание. Слушает определенную часть модели и умеет делать всякие флешевые анимации красивостей, на которые работает добрая доля отдела художников, и звуки, от местного звукорежиссера. Но, помимо этого, без нее не было бы интерактивности. Мало смотреть, хочется и "подергать" ) Вьюха честно сообщает контроллеру о пользовательских кликах, нажатиях на кнопки, голосовом управлении и прочих мультитачах. Контроллер, получая инфу от вьюх, меняет модель.

Вью - композитные. Похожи на дисплай лист.
Модель - тоже.
Контроллеры. Здесь особо не баловался, самостоятельно организовывал в виде команд. Но что-то мне подсказывает, что сделать иерархию контроллеров тоже можно.

Psycho Tiger
05.04.2010, 22:50
Да, спасибо, это мы уже всё разобрали =)
Почерпнул новое, однако же все вопросы выраженные постом раньше до сих пор остались нерешенными =(

cpu
06.04.2010, 00:09
Я почему-то думал раньше, что самый сложный(главный) код в модели.
А оказывается контролер всему голова, а модель это практически база данных? Я правильно понял?

dimarik
06.04.2010, 00:20
точно

Psycho Tiger
06.04.2010, 00:39
Новый вопрос созрел: хочу сделать V+MC, что я делаю:
Создаю класс, ни от кого ни исследующийся, в котором будет происходить вся логика, который будет изменять свои же свойства. Ему в конструктор передаю host:DisplayObjectContainer и в него добавляю вьюшку, которую эти же классом создаю. Когда нужно что-то обновить, вызываю у вьюшки метод render() или нечто вроде такого метода с нужными мне параметрами. Для MC + V делаю правильно?

etc
06.04.2010, 08:21
Psycho Tiger,
1) Типа того;
2) Модель снаружи приходит, у вьювера есть геттер-сеттер модели. То, что создает вьювер у себя внутри другие вьюшки отображающих элементы модели, контроллер не интересует. Максимум он подпишется у вьювера-контейнера на всплывающие события, либо сам контейнер ловит от вложенных вьюшек события и далее шлет результат (типичный пример — событие CHANGE у листа, которое формируется на основании событий SELECT у детей);

По классам: контроллер не занимается обновлением состояния вьювера. Он изменяет модель, модель шлет событие. Ссылка на модель передаётся контроллером вьюверу на стадии сборки триады. В случае критичности частоты вызова обновлений, можно написать и геттеры-сеттры «x», «y», так и метод setPosition. Симбиоз так сказать.

Ariel
06.04.2010, 09:04
2ЦПУ; 2ДИМАРИК ::
"точно" ни разу не точно. Это только одна из реализаций, причем не самая чистая. Мука почитать (и на ВИКИ посмотреть) так выходит, что все данные+логика тройки - в модель. Это будет классическая имплементация MVC. И ходят оне парами как M+VC, т.е. при замене Вью меняем и Контроллер к нему. На эти темы уже копий переломано!...

Котяра
06.04.2010, 09:47
Во всех реализациях MVC меня всегда смущали глобальности контроллера и модели. Если рассматривать модульную архитектуру приложения, то как мне кажется можно ввести понятие составной вью - который сам по себе может быть организован в виде mvc. Контроллер в таком вью является мостом между внутренними видами и внешним контроллером. Модель может быть как внутренняя так и ссылка на часть структуры внешней.
структура получается следующая:
M1 - C1 - V1(m2-v2-c2) а не M1(M2)- C1(C2)-V1(V2)
пример1:
Если рассматривать с точки зрения клиент - сервер, то клиент это тоже вид, который диспатчит интерактивные события и слушает изменения данных, либо прямые команды от сервера ( который в данном случае выполняет ф-ции контроллера и модели данных верхнего уровня)
пример 2:
готовая форма лобби вступления в игры. в качестве данных принимает список открытых игр - диспатчит событие присоединения к игре. как это внутри отображается не важно - там может быть куча отдельных окошек, списков комбобоксов итп, организованных по своим mvc правилам. Здесь контроллер выступате в роли слушателя внешней модели и меняет внутреннюю, также он слушает внутренние вьюшки - меняет внутреннюю модель и диспатчит внешние видовые события ( типа вступить в игру/ создать игру).
Для включения этого модуля(вида) в другую внешнюю MVC достаточно изменить "мостовую" часть контроллера. внтренняя структура остаётся неизменной.

А вообще я последнее время сильно охладел к MVC - как к универсальному решению) выхожу из стадии abstraction freek)
Хотя архитектуры проектов строю близко к МВЦ, но с учётом большей автономности модулей.
PS: А готовые фрэймворки - *****) более менее только mate использую, и то в силу его "необязательности".

Ariel
06.04.2010, 10:07
Главное, шоб оно оправдывало себя. Шоб не было такого, когда в порядке обновления Модели, надо пропускать событие с Вашего под-под-Вида через тучу Контроллеров БЕЗ ИЗМЕНЕНИЙ. Шоб не было MVC ради самого MVC. Возможно у Вас Контроллер выполняет роль Bridge (в M1 - C1 - V1(m2-v2-c2) а не M1(M2)- C1(C2)-V1(V2) и в пример 2).
Также иногда Контроллер просто на фиг выбрасывают из тройки как лишний ("необязательность"!). Т.к. весь инпут сразу в модель летит и обновляет ее эффективно. Т.е., имеем главное: отделяем представление от данных.

Art_133
06.04.2010, 13:08
Скажите пожалуйста, что делает эта строчка кода:
someSprite.addEventListener(MouseEvent.CLICK, super.dispatchEvent);
Я так понимаю что она диспатчит событие на которое был подписан Вьювер в Классе-Контроллере? Выходит что super вызывает методы, переменные не только у родителей но и может передать событие в Класс где был создан экземпляр?
Обьясните пожалуйста... Первый раз вижу такое...

mexoboy
06.04.2010, 14:17
Слушает определенную часть модели и умеет делать всякие флешевые анимации красивостей, на которые работает добрая доля отдела художников, и звуки, от местного звукорежиссера.
По логике вещей MVC, представление никак не связано с моделью. За передачу параметров представлению отвечает только контроллер. А задача контролера как раз и заключается из выдергивания необходимой бизнес-логики из модели и передачи готовенького представлению.

cpu
06.04.2010, 14:21
Ламерский вопрос.
При каких простых условиях говорят: "Вот это MVC!" ?
-----------------------------------------------------------------------------------

1. Т.е. что на что не должно иметь ссылок не при каких обстоятельствах?
-----------------------------------------------------------------------------------

2. Из Википедии:
Однако модель не зависит ни от представления, ни от поведения.Тогда как изменить определенные данные в модели, если я нажал что-то во View?
-----------------------------------------------------------------------------------

MrPoma
06.04.2010, 14:25
Скажите пожалуйста, что делает эта строчка кода:
someSprite.addEventListener(MouseEvent.CLICK, super.dispatchEvent);
Я так понимаю что она диспатчит событие на которое был подписан Вьювер в Классе-Контроллере? Выходит что super вызывает методы, переменные не только у родителей но и может передать событие в Класс где был создан экземпляр?
Обьясните пожалуйста... Первый раз вижу такое...Вызывает метод dispatchEvent. А поскольку объявлен он в супер-классе, пишут super.

etc
06.04.2010, 14:36
Тогда как изменить определенные данные в модели, если я нажал что-то во View?

Через контроллер. Точнее, как он решит, так и будет.

cpu
06.04.2010, 15:01
Через контроллер. Точнее, как он решит, так и будет. - получается контроллер имеет ссылку на модель. И меняет определенные данные через какой-нибудь set-метод?

Получается так:
1. View не имеет ссылок никуда, только рассылает события в контроллер.(данные введенные в input-поля хранит у себя, что бы их мог посмотреть контроллер через get-метод).
2. Контроллер имеет ссылку и на модель и на представление, и может работать с ними через их методы.
3. Модель отправляет события в контроллер если поменялись какие-то данные, и передает их ему через например set-методы. И наоборот.

В таком случае между View и model действительно нет прямой связи.
Но остается прямая связь между моделью и контроллером.

Art_133
06.04.2010, 15:13
Вызывает метод dispatchEvent. А поскольку объявлен он в супер-классе, пишут super.
Я думал что супер Клас имеется ввиду Класс который расширяет другой Класс. Здесь Controller не расширяет Viwer. Выходит что можно вызвать метод в классе где был объявлен экземпляр при помощи super?

etc
06.04.2010, 15:26
cpu
1) view имеет ссылку на модель;
2) Контроллер на них обоих;
3) Модель отправляет события вьюверу. Вьювер — контроллеру.

Psycho Tiger
06.04.2010, 15:31
Я думал что супер Клас имеется ввиду Класс который расширяет другой Класс. Здесь Controller не расширяет Viwer. Выходит что можно вызвать метод в классе где был объявлен экземпляр при помощи super?
Так и есть. Забудьте о super в этом примере. Пишите просто
addEventListener(Event.COMPLETE, dispatchEvent);
Это просто что то типа подписи "а это писал тру-флешер" :)

Я пишу с super только потому что мне необходимо, чтобы вот этот самый addEventListener был именно таким, каким я хочу - каким его сделали Adobe и ничто мне не может гарантировать, что завтра я для каких то других нужд переопределю addEventListener и dispatchEvent и мой сегодняшний код не перестанет работать. Маловероятно, конечно, но всё же... это мой бзик и моё право, к тому же так правильней :)

По теме MVC: *сейчас переделаю то, что писал вчера с новыми знаниями и отпишусь*

cpu
06.04.2010, 16:03
etc:
1) view имеет ссылку на модель;

Но ведь тогда view может напрямую менять данные в модели обойдя controller (и контроллер со своей бизнес-логикой остается неудел).
---------------------------------------------------------------
etc:
3) Модель отправляет события вьюверу. Вьювер — контроллеру.
Так как View имеет ссылку на модель, он может получит по этому событию данные из model для отображения, обойдя contoller(который опять неудел.)

=================================================================
P.S. Вообще какая главная цель MVC? Раньше я думал возможность подключать к программе множество представлений(view) и менять их хоть в горячую. Ну и создавать вложенные представления.

Psycho Tiger
06.04.2010, 16:43
Цель MVC - отделить то, что на экране от того, что происходит логикой. Короче, если проект расчитывался как консольный, а потом вдруг трах тибидох и хотим 3д - надо будет менять лишь вьюшку.


Главный класс:
package
{
import flash.display.Sprite;

public class JustMain extends Sprite
{

public function JustMain()
{
super();
var controller:Controller = new Controller(this);
}

}

}
Контроллер:
package
{
import flash.display.DisplayObjectContainer;
import flash.events.Event;
import flash.events.MouseEvent;

public class Controller
{
private var _model:Model = new Model();
private var _viewer:Viewer = new Viewer(_model);
private var _container:DisplayObjectContainer;
public function Controller(container:DisplayObjectContainer)
{
_container = container;
init();
}

private function init():void
{
_container.addChild(_viewer);
_viewer.addEventListener(MouseEvent.CLICK, onViewerClick);

}

private function onViewerClick(e:MouseEvent):void
{
_model.change(Math.random() * 400, Math.random() * 400);
}


}

}

Модель:
package
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;

public class Model extends EventDispatcher
{

//no getters/setters, just example
public var x:Number = 0;
public var y:Number = 0;

public function Model()
{
super(null);

}

public function change(x:Number, y:Number):void {
this.x = x;
this.y = y;
super.dispatchEvent(new Event(Event.CHANGE));
}

}

}

Вьюшка:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;

public class Viewer extends Sprite
{
private var _model:Model;
public function Viewer(model:Model)
{
super();
_model = model;
init();
}

private function init():void
{
var someSprite:Sprite = new Sprite();
someSprite.graphics.beginFill(0);
someSprite.graphics.drawCircle(0, 0, 50);
someSprite.graphics.endFill();
super.addChild(someSprite);
someSprite.addEventListener(MouseEvent.CLICK, super.dispatchEvent);

_model.addEventListener(Event.CHANGE, onModelChange);
}

private function onModelChange(e:Event):void
{
super.x = _model.x;
super.y = _model.y;
}



public function get model():Model { return _model; }

public function set model(value:Model):void
{
_model = value;
}
}

}

И серия вопросов вновь :) Спасибо, что помогаешь.
1) Вот классы выше - теперь это правильное MVC?
2) Да, действительно - вьюшка может менять что нибудь у модели и контроллер сойдёт с ума - получается, у этой триады даже пиша вьюшку надо быть аккуратным, потому что можешь всё сломать?
3) А кто от кого наследуется? Я так понимаю: controller -> Object, model - EventDispatcher, viewer - DisplayObject. Так?
4) Модельку передавать в конструктор вьюшки это хорошая практика, или всё таки лучше через сеттер? (вопрос граничит с бредом, знаю :D)
5) На той же википедии и на некоторых других сайтах пишут, что контроллер - лишь связующее, а вся бизнес логика в модели. Они не правы или с флешем тонкость какая?
6) Склоняюсь к мнению, что чистый MVC не в гигантских проектах нафиг не нужен, хотя мне нравится идея о MC + V. Такое существует вообще, контроллер с интегрированой моделью? Если да, то как там поступаем? Если контроллер уже имеет прямую ссылку на вьюшку, а в нём же интегрированна модель - то смысла в событии нет, можно отправлять напрямую или же ради сохранения полиморфизма и перехода после к чистой MVC следует остановится на событиях?

cpu
06.04.2010, 17:38
ФЛУД.
На днях пришла по почте "Приемы объектно-ориентированного проектирования. Паттерны проектирования" этих четырех авторов.
Там вроде написано про MVC, вечерком почитаю, отпишусь что они знают про MVC, люди вроде умные, из университетов)).

mexoboy
06.04.2010, 17:40
cpu, неужто открыл для себя книгу "Банды четырех"?

cpu
06.04.2010, 17:48
mexoboy пора когда-то это делать.)

Котяра
06.04.2010, 17:52
2) Да, действительно - вьюшка может менять что нибудь у модели и контроллер сойдёт с ума - получается, у этой триады даже пиша вьюшку надо быть аккуратным, потому что можешь всё сломать?
передавать в вид только IModel в котором, например,есть один только метод addChangeModelEventListener
сломать конечно можно но это будет уже очень явно.

Psycho Tiger
06.04.2010, 17:59
передавать в вид только IModel в котором, например,есть один только метод addChangeModelEventListener
сломать конечно можно но это будет уже очень явно.
Конечно, сломать можно всё делая это специально - когда говорил "сломать" подразумевалось конечно же "ненароком менял вьюшку, а полетела всё остальное".
С этим появляется ещё 2 вопроса:
7) Насколько это хорошая практика - делать по 40 разных событий для 40 изменений - то есть, если изменился угол поворота чей нибудь - не обновлять положение в пространстве, а лишь повернуть (то есть разбиение например updatePositionEvent на updateXYPositionEvent и updateRotationEvent)
8) Если передается только интерфейс, тогда вся инфа об обновлении должна поступить вместе с Event`ом, а не через геттеры от модели о нужной информации?

mexoboy
06.04.2010, 18:22
cpu
1) view имеет ссылку на модель;
2) Контроллер на них обоих;
3) Модель отправляет события вьюверу. Вьювер — контроллеру.

etc, ты ничего не путаешь? Представление и модель не должна иметь никаких связей (если мы говорим об оригинальном потерне MVC). Весь обмен данными идет через контроллер. В зависимости от типа модели (к примеру тонкой), контроллер может взять на себя роль прокси между моделью и представлением и обратно. Вся инициализация эвентов, логики, моделей - должна происходить в контроллере.

cpu
06.04.2010, 18:50
mexoboy +1

dimarik
06.04.2010, 23:43
2ЦПУ; 2ДИМАРИК ::
"точно" ни разу не точно. Это только одна из реализаций, причем не самая чистая. Мука почитать (и на ВИКИ посмотреть) так выходит, что все данные+логика тройки - в модель. Это будет классическая имплементация MVC. И ходят оне парами как M+VC, т.е. при замене Вью меняем и Контроллер к нему. На эти темы уже копий переломано!...

Привет! Ваш пост номер 13 и Вы выиграли поездку в кАННЫ на очередной фестиваль КО)
По сути. ТОЧНО есть точно.

Добавлено через 8 минут
1. View не имеет ссылок никуда, только рассылает события в контроллер

Просто рассылает события. Когда Вы кричите "Пожар!!", адресуете любому слышащему.

Добавлено через 10 минут
А вообще я последнее время сильно охладел к MVC - как к универсальному решению) выхожу из стадии abstraction freek)

Для тебя уже поздно ) Ты заражён MVC.

Добавлено через 14 минут

2) Да, действительно - вьюшка может менять что нибудь у модели и контроллер сойдёт с ума - получается, у этой триады даже пиша вьюшку надо быть аккуратным, потому что можешь всё сломать?

А мы дадим ей только читать )

Psycho Tiger
07.04.2010, 00:01
А мы дадим ей только читать )
Ну да, спасибо, это один из самых малозначимых вопросов на данный момент =)

Подписываюсь к вопросу о том, что нужно ли вьюшке иметь ссылку на модель и если нет - как получать данные об обновлении.

dimarik
07.04.2010, 00:02
etc, ты ничего не путаешь? Представление и модель не должна иметь никаких связей (если мы говорим об оригинальном потерне MVC).

Расскажите нам об оригинальном паттерне, пожалуйста.

Добавлено через 44 секунды
Ну да, спасибо, это один из самых малозначимых вопросов на данный момент =)

Подписываюсь к вопросу о том, что нужно ли вьюшке иметь ссылку на модель и если нет - как получать данные об обновлении.

Одназначна (с).

Ariel
07.04.2010, 00:15
Гр-н Димарик реально радует своими ч0ткими и однозначными ответами.
P.S. Поездку в Канны присылайте пожалуйста по электрической почте.

Котяра
07.04.2010, 09:56
Конечно, сломать можно всё делая это специально - когда говорил "сломать" подразумевалось конечно же "ненароком менял вьюшку, а полетела всё остальное".
С этим появляется ещё 2 вопроса:
7) Насколько это хорошая практика - делать по 40 разных событий для 40 изменений - то есть, если изменился угол поворота чей нибудь - не обновлять положение в пространстве, а лишь повернуть (то есть разбиение например updatePositionEvent на updateXYPositionEvent и updateRotationEvent)
8) Если передается только интерфейс, тогда вся инфа об обновлении должна поступить вместе с Event`ом, а не через геттеры от модели о нужной информации?
вот эти вопросы самые сложные ( во всяком случае для меня)
в своеё реализации mvc я диспатчил события для изменения любого отдельного свойства
подписывался также.
вот пример из рабочего проекта ( as2)
class ru.k0t0vich.mvc.models.Model extends EventDispatcher
{

public function Model(eventParentLink)
{
eventParent = eventParentLink;
}

/**
* Диспатчим событие об изменении структуры
* @param field - имя поля (должно присутьствовать в классе, иначе генерируется ошибка времени выполнения)
*/
public function update(field:String):Void
{
if (field == undefined) field = "";
var event: ModelEvent= new ModelEvent(ModelEvent.CHANGE+field);
// Проверка на доступность свойства
if (field != "")
{
try
{
event.field = this[field];
}
catch (e:Error)
{
trace (e);
}
dispatchEvent(event);
}
else
{
event.field = this;
dispatchEvent(event);
}


}

}
подписка во вью:
public function addChangeModelFieldListener(field:String,listener:Function,scope:Object):Void
{
_model.addEventListener(ModelEvent.CHANGE + field, listener,scope);
// регистрируем для отписки от ВСЕХ событий модели
_modelFieldEventListenersArray.push( { event:ModelEvent.CHANGE + field, listener:listener,scope:scope } );
}

пример подписки:
/**
* Инициализацие хэндлеров изменения модели
*/
private function initModelListeners()
{
addChangeModelFieldListener(SlotModelField.LINES, showLinesByModel, this);
addChangeModelFieldListener(SlotModelField.FREESPINS, updateFreespinsCounter, this);
addChangeModelFieldListener(SlotModelField.WIN, updateFreespinsCounter, this);
}


косяков в такой реализации много ( нет строгой типизации итп) но многое лечится вводом класса констант SlotModelField. доступ к геттерам модели у меня кстати тоже так сделан,
private function updateFreespinsCounter(e:ModelEvent):Void
{
freespinsCounterWindow.freespins = model[SlotModelField.FREESPINS];
freespinsCounterWindow.cash = model[SlotModelField.WIN];
}
хотя можно сделать в IModel геттеры этих свойств - я не сделал т.к. при добавлении публичных обновляемых свойств в модели пришлось бы редактировать уже 3 класса ( Model, ModelField и IModel) а не 2 (Model, ModelField)

модель обновляется таким образом:
public function get totalBet():Number { return _totalBet; }

public function set totalBet(value:Number):Void
{
_totalBet = value;
update(SlotModelField.TOTAL_BET);
}

В общем практика показала относительное удобство такого подхода..
хотя могло бы быть и лучше..

PS: основная "неправильность" моего подхода была в методе update который создаёт эвент с динамическим типом field. Практика показала, что на самом деле это поле практически не используется при слушании событий, т.к. у вида есть ссылка на нужный геттер и он может его просмотреть самостоятельно, а не в качестве свойства события..
так-что можно смело переписать метод update так:
public function update(field:String):Void
{
if (field == undefined) field = "";
var event: ModelEvent= new ModelEvent(ModelEvent.CHANGE+field);
dispatchEvent(event);

}

etc
07.04.2010, 10:14
Но ведь тогда view может напрямую менять данные в модели обойдя controller
Может, только это не в его компетенции.

Так как View имеет ссылку на модель, он может получит по этому событию данные из model для отображения, обойдя contoller(который опять неудел.)
Ещё раз: может ещё не означает, что так и должен делать. Вы можете дома открыть газ в плите и зажечь спичку через пару-тройку минут, но почему-то этого не делаете.

mexoboy
07.04.2010, 10:21
Расскажите нам об оригинальном паттерне, пожалуйста.

Тут собственно все описано: http://www.books.ru/shop/books/352130

etc
07.04.2010, 10:32
1) Вот классы выше - теперь это правильное MVC?
В целом на то, как это делал бы я, уже похоже.

2) Да, действительно - вьюшка может менять что нибудь у модели и контроллер сойдёт с ума - получается, у этой триады даже пиша вьюшку надо быть аккуратным, потому что можешь всё сломать?
Оно, конечно, может менять модель, но опять же, если вам приспичило спрыгнуть с балкона, он вам не сможет помешать.

3) А кто от кого наследуется? Я так понимаю: controller -> Object, model - EventDispatcher, viewer - DisplayObject. Так?
Чаще всего — да. Но и контроллер тоже может события рассылать.

4) Модельку передавать в конструктор вьюшки это хорошая практика, или всё таки лучше через сеттер? (вопрос граничит с бредом, знаю :D)
Это зависит от задачи, если планируется переиспользование вьювера для отображения различных данных, то сеттер предпочтительнее.

5) На той же википедии и на некоторых других сайтах пишут, что контроллер - лишь связующее, а вся бизнес логика в модели. Они не правы или с флешем тонкость какая?
Нет тонкости, дело в понятии, что есть модель. По сути, ей требуется лишь хранить данные. Бизнес-логика очень часто зависит от действий пользователя, но не все действия пользователя должны быть известны модели.

Добавлено через 8 минут
etc, ты ничего не путаешь? Представление и модель не должна иметь никаких связей (если мы говорим об оригинальном потерне MVC). Весь обмен данными идет через контроллер. В зависимости от типа модели (к примеру тонкой), контроллер может взять на себя роль прокси между моделью и представлением и обратно. Вся инициализация эвентов, логики, моделей - должна происходить в контроллере.
Что касается «оригинальности», то достаточно картинки с Википедии:
http://upload.wikimedia.org/wikipedia/commons/thumb/2/2e/ModelViewControllerDiagram.svg/321px-ModelViewControllerDiagram.svg.png
Совершенно точно у View есть ссылка на модель.

У модели нет конкретной ссылки на представление. Ссылка на уровне приложения конечно есть, но она лишь на уровне подписчика на изменения, поэтому и выполнена пунктиром.

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

Добавлено через 10 минут
7) Насколько это хорошая практика - делать по 40 разных событий для 40 изменений - то есть, если изменился угол поворота чей нибудь - не обновлять положение в пространстве, а лишь повернуть (то есть разбиение например updatePositionEvent на updateXYPositionEvent и updateRotationEvent)
Я предлагаю исходить из здравого смысла. Если изменения одного рода, то не смысла для каждого из них делать своё событие.

8) Если передается только интерфейс, тогда вся инфа об обновлении должна поступить вместе с Event`ом, а не через геттеры от модели о нужной информации?
А что мешает описать геттеры и в интерфейсе? Менять не можем, а читать вполне себе да.

cpu
07.04.2010, 14:31
в model-и есть set-метод и get-метод.
Как сделать, что бы view НЕ мог работать с set-методом, но мог работать с get-методом? И при этом открыть доступ к обоим методам controller-у?

etc
07.04.2010, 14:41
в model-и есть set-метод и get-метод.
Как сделать, что бы view НЕ мог работать с set-методом, но мог работать с get-методом? И при этом открыть доступ к обоим методам controller-у?

Указать в типе сеттера модели вьювера IModel, а не саму Model. В IModel описать доступные геттеры. Но вообще, это по сути защита от дурака.

cpu
07.04.2010, 14:50
признаюсь: не знаю что такое IModel.
====================================================
Но вообще, это по сути защита от дурака. - это я понимаю, так спрашиваю, на будущее.

Psycho Tiger
07.04.2010, 15:08
IModel интерфейс, который имплементит Model.
Всем большое спасибо, особенно etc, уже понимаю суть.
Ещё 2 вопроса:
etc, а что нужно ещё поменять в той реализации что я дал, чтобы это ещё больше стало похоже на то, как написал бы ты? В голову лезет только добавление интерфейсов, и то что во втором вопросе.
Собственно второй вопрос: а есть ли какие то общие-базовые-классы для модели, вьюшки и контроллера? Тот же pureMVC - честно не понимаю, как MVC можно обернуть в фреймворк - наверняка там цепочка наследования controller -> controller base class -> object (или этих звеньев до object больше) и назревает вопрос - а какой функционал туда можно выносить? Голова не позволяет выделить что то общее, помимо сохранение ссылки на модель или вьюшку - но новый класс ради 2 строчек... как то бредово.

etc
07.04.2010, 15:15
etc, а что нужно ещё поменять в той реализации что я дал, чтобы это ещё больше стало похоже на то, как написал бы ты?
Добавить нужно в модель проверки на совпадение с текущими значениями, чтобы не слать событие лишний раз. Кроме того, это спасёт от переполнения стека в случае, когда существует прямая связь между свойствами представления и модели. И в сеттере модели во вьювере необходима такая же проверка на совпадение с текущей моделью и отписка от событий старой модели.

Собственно второй вопрос: а есть ли какие то общие-базовые-классы для модели, вьюшки и контроллера? Тот же pureMVC - честно не понимаю, как MVC можно обернуть в фреймворк - наверняка там цепочка наследования controller -> controller base class -> object (или этих звеньев до object больше) и назревает вопрос - а какой функционал туда можно выносить? Голова не позволяет выделить что то общее, помимо сохранение ссылки на модель или вьюшку - но новый класс ради 2 строчек... как то бредово.
Можно каждому контроллеру создать свою модель. Можно в базовых классах модели организовать древовидность.

Psycho Tiger
07.04.2010, 15:50
Добавить нужно в модель проверки на совпадение с текущими значениями, чтобы не слать событие лишний раз.
Совпадения значения сейчас? То в сеттере модели:
if (currentValue==value) return;
currentValue=value;
super.dispatchEvent(...)?
Можно в базовых классах модели организовать древовидность.
О какой древовидности идёт речь? Не вижу закономерностей у 2 произвольных моделей или думаю не о том =(

etc
07.04.2010, 19:10
Совпадения значения сейчас? То в сеттере модели:
if (currentValue==value) return;
currentValue=value;
super.dispatchEvent(...)?
Ну да, подобные проверки на текущее значение вообще в любом сеттере надо писать.

О какой древовидности идёт речь? Не вижу закономерностей у 2 произвольных моделей или думаю не о том =(
Имеется ввиду структура данных, контейнер-список и конкретные элементы. Последние о родителе особо ничего не знают, но являются также элементами модели. Сама модель похожа на структуру DisplayObject-ов.

Psycho Tiger
07.04.2010, 20:27
Имеется ввиду структура данных, контейнер-список и конкретные элементы. Последние о родителе особо ничего не знают, но являются также элементами модели. Сама модель похожа на структуру DisplayObject-ов.
Ну да, это я понял, спасибо. Только мне не совсем ясна практическая ценность такого подхода. Какие плюсы?

etc
08.04.2010, 09:44
Ну да, это я понял, спасибо. Только мне не совсем ясна практическая ценность такого подхода. Какие плюсы?

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

Psycho Tiger
08.04.2010, 19:47
Суть понял, однако древовидные модели применять пока не буду - не представляется в данный момент нужным.

Спасибо большое, теперь я разобрался. Наверное, в усвоении сейчас поможет только практика. Ещё раз огромное спасибо)

cpu
08.04.2010, 23:01
в model-и есть set-метод и get-метод.
Как сделать, что бы view НЕ мог работать с set-методом, но мог работать с get-методом? И при этом открыть доступ к обоим методам controller-у?

ответил etc, что через интерфейс IModel.
=============================================
Если кому не лень, напишите в коде как это будет выглядеть.:rolleyes:

Psycho Tiger
08.04.2010, 23:29
package game
{
public interface ILandMovable
{
function get line():int;
}

}

fljot
11.04.2010, 13:14
А ещё часто пишут, что модель занимается бизнес-логикой.
Вот пример — видеоплеер. Заканчивается проигрывание видюшки, модель диспатчит соотв. событие. Кому лучше дальше принять решение проигрывать ли следующее/случайное видео из списка или остановится? На основании какого-нибудь mediaPlayer.config.repeatMode и mediaPlayer.config.shuffle ?

etc
11.04.2010, 19:11
Кому лучше дальше принять решение проигрывать ли следующее/случайное видео из списка или остановится?
Контроллеру.

dimarik
13.04.2010, 01:06
Тут собственно все описано: http://www.books.ru/shop/books/352130

Замечательная книжка. Только я не нашел там описание MVC в качестве паттерна. Дальнейшие рассуждения об "оригинальности" "паттерна" MVC считаю актом вероломства.

Psycho Tiger
13.04.2010, 01:40
Кстати, вот сейчас интересный вопрос постиг:
Делаю игру, она 2.5д-шная, позиционирование объектов идёт как в 3д, но объекты являются уже отрисованными картинками и они просто поворачиваются нужным кадром к зрителю, создавая эффект 3д (короче, поворот на 360 кадрами мувиклипа, и крутим как будто бы в 3д). Странное чувство, но я уже даже не представляю, как это можно сделать без MVC... он чертовски заразный :D

Дак вопрос в чем - камера следует всегда за игроком и её можно крутить (только в одном направлении, конечно, иначе пререндер не имел бы смысла). В движке я переопределил методы поворота камеры с изменением модели PlayerModel (как никак это камера от игрока, поэтому туда засунуть считаю допустимым) и её же передаю другим объектам, которые должны крутится (чтобы они знали, когда нужно повернуться и куда). Это допустимо с точки зрения MVC, передавать не свою модель?

Котяра
13.04.2010, 09:31
Если вид зависит от PlayerModel - то это его модель тоже. Вообще разделение на "своя" - "не своя" условно. Но на вашем месте я бы вынес данные о камере в Model.cameraData - для более читабельного кода. тогда CharacterView [i] следит за Model.characterData[i] и за Model.cameraData, что вполне логично.
Тут, кстати, пригодилась бы древовидная реализация модели с всплывающими событиями..

Tahion
13.04.2010, 13:56
Замечательная книжка. Только я не нашел там описание MVC в качестве паттерна. Дальнейшие рассуждения об "оригинальности" "паттерна" MVC считаю актом вероломства.

Да неплохая, она у меня даже есть :). Но вобщемто там многие патерны не описаны существующие)

Psycho Tiger
13.04.2010, 15:56
Тут, кстати, пригодилась бы древовидная реализация модели с всплывающими событиями..Можешь объяснить, что и куда? Я не понимаю, куда там дерево =\

Но на вашем месте
Давай на ты, вроде не первый день общаемся?

И да, у меня только один большой MVC, отвечающий за игрока и камеру, мелкие объекты вроде партиклов вообще идут одни классом, посложнее - а ля такие же юниты, как игроки - связкой V + MC. Может быть, это идиологически неправильно, но я руководствовался здравым смыслом.

Котяра
13.04.2010, 18:17
При работе с партиклями, да и вообще с большим количеством объектов ( при z-сортировке например) mvc тоже не применяю - очень накладно. Лучше контроллером явно менять параметры видов.
Древовиная модель:
в твоем примере имеем что-то вроде:
model {cameraModel{angleData,x,y},charModel1{data},charModel2{data}..,}
инициализация и подписка
charView1.model = model
// тут уже можно по-разному организовать
model.addEventListener("Обновление_cameraModel",func);
model.addEventListener("Обновление_cameraModel_angleData",func);
model.cameraModel.addEventListener("Обновление__angleData",func);

model.charModel1.addEventListener("Обновление_data",func);
model.addEventListener("Обновление_charModel1_data",func);
события, соответственно, должны всплывать.

Psycho Tiger
13.04.2010, 18:51
А зачем событиям всплывать?

etc
13.04.2010, 19:25
А зачем событиям всплывать?

Для удобства.
Вообще, под древовидной моделью я имел в виду не просто ссылки у родителя, а именно список детей и методы, схожие с методами DisplayObjectContainer.

Psycho Tiger
13.04.2010, 19:52
Для удобства.
Гм, ну понятное дело что не в ущерб )
Я к тому что если есть подписка, например
model.cameraModel.addEventListener("Обновление__angleData",func);

То зачем событию всплывать, чтобы его можно было поймать через
model.addEventListener("Обновление__angleData",func);
Или я опять не о том?
Вообще, под древовидной моделью я имел в виду не просто ссылки у родителя, а именно список детей и методы, схожие с методами DisplayObjectContainer.
Гм, а я подумал о том, что предложил Котяра. Можно пример абстрактный тогда?

etc
13.04.2010, 21:21
Можно пример абстрактный тогда?

var container:DataContainer = new DataContainer();
var data:Data = new Data();
container.addChild(data);
container.addChild(new MegaData());
container.addChild(new ItemData());

Psycho Tiger
13.04.2010, 21:55
Да, это я понял, я немного о другом спрашиваю.
Ну вот отталкиваясь от примера, что ты мне написал:
container.getDataAt(0)
В чем плюсы перед обычным объектом?
var obj:Object={megaData: new MegaData()};
И почему была принята политика называть методы схоже с DisplayObjectContainer`ом?

etc
13.04.2010, 22:06
Чтобы обеспечить зеркальность структуры вьюверов и модели.

Psycho Tiger
13.04.2010, 22:14
Хм..
То есть примерно для таких нужд?
var mc:SomeMovieClip=new SomeMovieClip();
mc.addChild(new OtherMovie());
(mc.getChildAt(0) as OtherMovie).model=bigModel.getModelAt(0);
Если да, то в голове пока что не укладывается удобство от такого "удобства".

etc
13.04.2010, 22:21
Нет, имеется ввиду, что, например, вместе с событием REMOVED элемента модели удалится и вьювер, отображающий данный элемент. К примеру, в обычном List.

Psycho Tiger
13.04.2010, 22:56
Ааа, и удалив модель земного шара мы удалим одним махом и модели всех землян вместе с вьюшками. Теперь стало понятно, спасибо )

etc
14.04.2010, 17:16
Нет, я имел ввиду удаление одного землянина с земли одновременно с удалением оного из базы данных.

Котяра
15.04.2010, 10:36
То зачем событию всплывать, чтобы его можно было поймать через
model.addEventListener("Обновление__angleData",func);
Или я опять не о том?
Я имел ввиду именно, то.
У меня тоже древовидная структуру, только в отличии от etc - я не делал аналог DisplayObject с addChild и.т.п.
У меня просто в конструкторе модели - передаётся ссылка на парент (которую, в принципе можно и сменить потом, но мне пока ни разу не понадобилось.)

model.submodel = new Submodel(model);
// вернее чаще так
в классе модели:
submodel = new Submodel(this);


причём основную модель я пару-раз делал ребёнком контроллера - тогда все события модели доходят до контроллера всплытием.
пример : слушаем смерть землянина:
в контроллере
model.addUpdateFieldListener(HumanModelField.IS_DEAD,removeHuman);

public function removeHuman(e:ModelEvent)
{
var deadHumanModel:HumanModel = e.target as HumanModel;
var isDead :Boolean= e.field;
if(isDead )
{
//удаляем подмодель из модели
// удаляем вид связанный с моделью
// прочеее
}
}

т.е. тут контроллеру не надо подписывать на события модели каждого человека. он просто слушает все сообщения о смерти)

etc
15.04.2010, 10:40
currentTarget? Ты уверен? :)

Котяра
15.04.2010, 11:07
currentTarget? Ты уверен? :)
блин, скосячил - target конечно..)

Psycho Tiger
15.04.2010, 18:18
т.е. тут контроллеру не надо подписывать на события модели каждого человека. он просто слушает все сообщения о смерти)
Ааа... всё, теперь всё стало понятней) Только вот:
var isDead :Boolean= e.field;
Ты посылаешь в событии то что нужно узнать обработчику?
И вот тут:
model.addUpdateFieldListener(HumanModelField.IS_DEAD,removeHuman);
покажи код метода addUpdateFieldListener, не очень ясно почему не просто addEventListener )

Котяра
16.04.2010, 09:42
тут (http://www.flasher.ru/forum/showpost.php?p=898584&postcount=38) у меня "не очень" ООП-ный код используется..
ModelEvent имеет свойство field:*
addUpdateFieldListener===addChangeModelFieldListener переименовал,а вообще можно field и не использовать.
public function removeHuman(e:ModelEvent)
{
var deadHumanModel:HumanModel = e.target as HumanModel;
var isDead :Boolean= deadHumanModel.isDead;
if(isDead )
{
...

Psycho Tiger
16.04.2010, 16:34
Угу, мне вот второй способ кажется логичней. Лучше спросить кому надо, чем знать это всем.
А вот это зачем? Для какой цели?

_modelFieldEventListenersArray.push( { event:ModelEvent.CHANGE + field, listener:listener,scope:scope } );

Котяра
16.04.2010, 16:58
это регистрация для автоматического удаления всех листенеров

Psycho Tiger
16.04.2010, 20:36
Понял. Спасибо за разъяснения.

dimarik
20.04.2010, 00:25
Да неплохая, она у меня даже есть :). Но вобщемто там многие патерны не описаны существующие)

Например?

Добавлено через 5 минут
У меня тоже древовидная структуру, только в отличии от etc - я не делал аналог DisplayObject с addChild и.т.п.
У меня просто в конструкторе модели - передаётся ссылка на парент (которую, в принципе можно и сменить потом, но мне пока ни разу не понадобилось.)

Стандартный GOF-паттерн Composite. Что у тебя, что у Дениса, точнее, у Блуда.

Добавлено через 11 минут
причём основную модель я пару-раз делал ребёнком контроллера - тогда все события модели доходят до контроллера всплытием.

А я видел фильм с Арнольдом Шварценеггером, "Total Recall". И мне понравилась тетя с тремя сисями. Ну хоть и не по-человечески, а то и приятно ).

Добавлено через 18 минут
model.addUpdateFieldListener(HumanModelField.IS_DEAD,removeHuman);


Откуда такая ненависть к абстракции? В продукте лучше не упоминать о "concrete product" всуе. Здесь подойдет какой-нибудь Event.COMPLETE, вместо ХУМАНМОДЕЛ.МЕРТВ.

Я уж молчу о нововведении "addUpdateFieldListener". Чем EventDispatcher не угодил? Не следует множить сущее без необходимости (http://ru.wikipedia.org/wiki/%D0%91%D1%80%D0%B8%D1%82%D0%B2%D0%B0_%D0%9E%D0%BA%D0%BA%D0%B0%D0%BC%D0%B0).

Котяра
27.04.2010, 17:53
Откуда такая ненависть к абстракции? В продукте лучше не упоминать о "concrete product" всуе. Здесь подойдет какой-нибудь Event.COMPLETE, вместо ХУМАНМОДЕЛ.МЕРТВ.

Я уж молчу о нововведении "addUpdateFieldListener". Чем EventDispatcher не угодил? Не следует множить сущее без необходимости (http://ru.wikipedia.org/wiki/%D0%91%D1%80%D0%B8%D1%82%D0%B2%D0%B0_%D0%9E%D0%BA%D0%BA%D0%B0%D0%BC%D0%B0).

addUpdateFieldListener (ИМЯ_ПОЛЯ_МОДЕЛИ, слушатель);
вместо
addEventListener (ИМЯ_СОБЫТИЯ_ИЗМЕНЕНИЯ_ПОЛЯ_МОДЕЛИ, слушатель);

поэтому и
HumanModelField.IS_DEAD=="isDead".
Никакого "умножения сущностей" нет - есть элементарнейшая лень, которая - двигатель прогресса. :) Да - не по-человечески, не по ООПовски, но код читабельный и понятный.
Появились мысли сделать систему на сигналах, а не на событиях - там наверное получится покрасивее..

Psycho Tiger
12.06.2010, 00:08
Вот кстати созрели новые вопросы:

1) Взглянул на схему etc. Не понял, почему бабблинг идёт по дате, и уходит в контроллер. С чего контроллеру то нужны события даты (это модель так обозвана, или это ерунда из базы данных?)

2) Всё чаще код в контроллерах у меня сокращается, и в модели появляются много методов, таких как addLine() и на них похожих. В итоге, по идее контроллер должен заниматься такой ерундой, как подготовить что нибудь и добавить в модель, а у меня модель сама подготавливает что ей надо (не в ущерб гибкости, конечно) и добавляет в себя. Насколько это плохо?

Котяра
12.06.2010, 01:29
1)дата это данные модели(подмодели) и не уходят они, а показывают что есть связь с контроллером который их меняет. но могу ошибаться - денис лучше расскажет)
2)это наоборот очень хорошо, если модель сама себя описывает и меняет - а контроллер по сути это сущность которая инициализирут и контролирует)

etc
12.06.2010, 10:21
1) Дата только хранит данные. Контроллер потенциально может слушать модель, т. к. он не единственный контроллер, который может её изменять.

2) Если речь идёт только о том, чтобы добавить некие данные на основе входящих аргументов, то это вполне неплохо. Если же модель начинает содержать логику, в результате которой изменяются другие составляющие модели (вроде списывания денег с персонажа при добавлении предмета) — то это не её обязанность.

Psycho Tiger
12.06.2010, 12:24
1) Ну дата тогда получается что это модель? Модель тоже только хранит данные. Ну и оповещает об изменении.

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

Почему то думал, что поступаю не совсем хорошо, но забил на правила хорошего тона когда понял, что мне это удобно, а тут оказалось что это ещё и правильно. Здорово %)

etc
12.06.2010, 15:44
1) Да, дата — это модель;

2) В таком варианте такие методы вполне себе оправданы и должны быть у модели, а не у контроллера.

Psycho Tiger
13.06.2010, 17:16
Понятно, спасибо.

Psycho Tiger
03.09.2010, 16:53
Собственно, меня долгое время смущало вот это:
5) Отображает вьювер, изменяет контроллер. И у того и другого есть ссылки на базу.
1) Имеется ввиду модель или реальная база данных? Когда я спрашивал я имел ввиду внешнюю БД, например, сервер.

2) Как будет грамотнее: заставить модель получить информацию с базы (и периодически её обновлять, например сделать в ней сокет, а при поступлении байтов просить контроллер что-то сделать) или заставить это делать контроллер, периодически записывая результаты в модель?

etc
03.09.2010, 18:14
1) Нет, это иерархическая модель;

2) Можно написать отдельный контроллер модели, который работает с соединением и помещает приходящие данные в модель.

Psycho Tiger
03.09.2010, 18:26
2) То есть одна модель на 2 контроллера (один работает с сервером, другой уже берёт данные и обрабатывает их)? Понятно, спасибо.

etc
03.09.2010, 18:29
Нет, два контроллера на одну модель. Один «побольше», логический, второй «поменьше», для работы с сервером через соединение и засовыванием данных в модель. У обоих контроллеров есть ссылка на модель. Между контроллерами может быть вполне себе событийная связь (от младшего к старшему) и как минимум прямая (вызов методов от старшего к младшему).

Psycho Tiger
03.09.2010, 18:33
То есть одна модель на 2 контроллера
Нет, два контроллера на одну модель.
Я не то же самое сказал? =)

Спасибо большое )

etc
03.09.2010, 18:54
Я не то же самое сказал?
Не совсем, обязанности были другие.

Zebestov
08.09.2010, 03:15
а как всплывают события не у экранных объектов? какая-то собственная реализация с генерацией только что принятоно от "ребенка" события с помощью e.clone()? или я что-то пропустил :umnik2:

Котяра
08.09.2010, 03:24
я, например, в реализации евентов для as2 (http://www.flasher.ru/forum/blog.php?b=140), диспатчил срузу у парента, если событие всплываемое и у парента есть dispatchEvent..

Zebestov
08.09.2010, 03:55
ну это на один уровень вверх. а если надо более абстрактно? ну в принципе понял — руками.

Psycho Tiger
08.09.2010, 11:23
while (parent) dispatchEvent
В целом как то так.

Вообще мне не нравится нативная система событий в парадигме моделей у MVC. Мне не нравится идея клонирования, чтобы не попортить target и фазу, на мой взгляд это слишком дорого для этого. У меня в голове крутятся абстрактные идеи сделать свою систему событий с блекджеком, но садиться и думать основательно нет времени.

Котяра
08.09.2010, 11:40
сигнал-слот?

etc
08.09.2010, 12:08
Мне не нравится идея клонирования, чтобы не попортить target и фазу, на мой взгляд это слишком дорого для этого.
Что, мы опять делаем приложения, вычисляющие геном человека за 30 секунд с триллионами итераций?

Psycho Tiger
08.09.2010, 12:36
Что, мы опять делаем приложения, вычисляющие геном человека за 30 секунд с триллионами итераций?
Если есть мысли, как это можно сделать лучше - то почему это плохо?

@Котяра: что-то вроде, но более похожий на нативный EventDispatcher. Это мысли, ещё не факт что даже попробую это сделать.

etc
08.09.2010, 12:46
Если есть мысли, как это можно сделать лучше - то почему это плохо?
Лучше != удобнее. Скопировать событийную модель displayobject-ов — это удобно. Даже если она будет медленнее, чем варианты с прямым вызовом.

Psycho Tiger
08.09.2010, 14:42
Я тебя не понял.
Я делаю событийную модель как у DO - это удобно, но не лучше?
Что подразумевается под лучше?

etc
08.09.2010, 14:47
Что подразумевается под лучше?

Это как раз у тебя надо спросить.

Psycho Tiger
08.09.2010, 15:01
Я прекрасно понимаю, что понятие "лучше" чисто субъективное )
Мне интересна твоя точка зрения, почему событийная модель DO для тебя не лучше.

etc
08.09.2010, 15:08
почему событийная модель DO для тебя не лучше.

Я где-то об этом сказал? Это для тебя она не лучше.

Psycho Tiger
08.09.2010, 15:14
Блин.
Если есть мысли, как это можно сделать лучше - то почему это плохо?
Лучше != удобнее. Скопировать событийную модель displayobject-ов — это удобно. Даже если она будет медленнее, чем варианты с прямым вызовом.
Я хочу скопировать событийную модель DO, но для не DO - то есть что-то вроде паттерна composite с хорошей событийной моделью.
Ты говоришь, что лучше не значит что это удобнее и тут же говоришь что если скопировать событийную модель DO - то это удобно. Таким образом я считаю это лучше, ты считаешь это удобней. Если всё верно - я не понимаю о чем пошел спор.

etc
08.09.2010, 15:16
Пост #97 (http://www.flasher.ru/forum/showpost.php?p=934277&postcount=97)

Psycho Tiger
08.09.2010, 16:20
Ок, не так друг друга поняли.
Ты используешь нативный EventDispatcher, а в случае нужды бабблинга просто редиспатчишь в "родителе"? Или используешь DO, как dimarik?

etc
08.09.2010, 16:36
Ок, не так друг друга поняли.
Ты используешь нативный EventDispatcher, а в случае нужды бабблинга просто редиспатчишь в "родителе"? Или используешь DO, как dimarik?

Первое.

Psycho Tiger
08.09.2010, 16:45
Понятно, спасибо.

Zebestov
10.09.2010, 04:48
Сразу говорю: MVC — только разбираюсь, UML — вообще никогда :quiet: не ругайте.
Вот набросал схемку:

http://s39.***********/i086/1009/9b/39f0a12eb88f.jpg

Допустим решил я сделать Menubar.

Model хранит массив кнопок (id, title)

View рисует все кнопки, что есть в Model, по событию CHANGE.

Controller запрашивает у API сервера (через другой контроллер — APIController) список доступных пользователю кнопок, парсит ответ и записывает в модель уже в виде требуемого массива. Также по нажатию на кнопку контроллер получает id кнопки и предпринимает определенные действия.

Обращение к API происходит вызовом метода APIController#request(req:String):APILoader, т.е. мы подаем запрос в неком универсальном формате (например синтаксис Facebook Graph API нравится), метод создает новый APILoader (расширяет наверное URLLoader) и возвращает его, чтобы основной контроллер мог подписаться на его COMPLETE и взять именно свою data по факту загрузки.

Что правильно, что ошибка, что чушь по неопытности — хочу как-то разобраться в этом вопросе основательно.

etc
10.09.2010, 11:56
Непонятна роль APIController-а. Точнее понятна, но результат парсить должен именно он и выдавать его уже в виде удобоваримых данных MenubarController-у. Либо парсить должна сама модель. И возвращать APILoader не имеет смысла, слушать его должен сам APIController, а по окончании загрузки слать событие COMPLETE. Сейчас в APIController получается единственный метод, содержащий три строчки.

Tr1te
10.09.2010, 13:11
Не понимаю зачем сонтроллеру передавать ссылку на себя моделе и вьюверу, если они являются детьми и они могут к нему обращаться как parent.?

etc
10.09.2010, 13:14
Tr1te, модель ничего не знает о контроллере и вьювере, если что. А обращение к родителю в принципе не есть ООП-подход.

Obi
10.09.2010, 13:29
Простите за оффтоп, но прицепите уже эту тему вверх раздела. Полезность ее зашкаливает.

etc
10.09.2010, 13:31
Простите за оффтоп, но прицепите уже эту тему вверх раздела. Полезность ее зашкаливает.

Done.

Zebestov
10.09.2010, 14:03
Непонятна роль APIController-а. Точнее понятна, но результат парсить должен именно он и выдавать его уже в виде удобоваримых данных MenubarController-у. Либо парсить должна сама модель.
Предполагалось, что APIController — это общий для всего приложения класс, задача которого обеспечивать запросы к API серверу текущей среды (vkontakte, facebook и также просто сайт приложения в сети интернет). Он единственный знает (при инициализации), в какой среде сейчас запущено приложение и делает выборку нужных данных соответствующим образом. Поэтому, в силу отличий API разный сетей, для запросов к нему внутри приложения формируется некий универсальный формат. То же для ответов.
Вот теперь больше информации о том, что я хочу сделать. Все очень сырое и совет/отбраковка приветствуются.
Из всего этого я подумал, что APIController парсить ничего не должен. Да и слово парсить наверное громко для процесса из моей схемы... это скорее выборка только нужных данных для MenubarModel, который сейчас должен иметь по каждому пункту меню только его id и title. Вот такой был ход мысли.

Насчет "парсить в модели". По сути модель тоже в праве знать о формате ответов на API запросы, принятом в приложении, чтобы самостоятельно разобрать вошедший Object и сохранить в себе только нужное. Так будет правильней? (а то она вообще тогда какая-то вот-вот нафиг ненужная)


И возвращать APILoader не имеет смысла, слушать его должен сам APIController, а по окончании загрузки слать событие COMPLETE.
Единственная причина такой схемы — обеспечить ожидание именно своих данных в случае, когда к APIController-у обратится подряд несколько контроллеров каждый со своим "заказом". Ведь если слушать COMPLETE самого APIController, то поди разбери чей это ответ пришел? Не ну можно придумать схему разбора по какому-то requestID, который возвращал бы метод request() (сейчас он возвращает ссылку на APILoader). Так будет правильней?

Сейчас в APIController получается единственный метод, содержащий три строчки.
Ну выше я уже описал, что по сути внутри у APIController целый механизм, ограждающий приложение от среды с ее особенностями.

Спасибо за ответы! Надеюсь разобраться с вашей помощью.

etc
10.09.2010, 14:34
Zebestov, тогда APIController должен отдавать в универсальном формате, скажем, в виде экземпляра какого-нибудь универсального APIUserData. Парсить — это к примеру из xml/json в этот самый APIUserData. В модель можно сувать через addAPIUser.

Кроме того, не вижу никакого смысла делать запросы к нему из нескольких мест, этим должен заниматься основной контроллер приложения, а APIController в ответ будет вызывать методы в нём (через client).

Zebestov
10.09.2010, 14:49
Кроме того, не вижу никакого смысла делать запросы к нему из нескольких мест, этим должен заниматься основной контроллер приложения, а APIController в ответ будет вызывать методы в нём (через client).
Чувствую, что что-то правильное, но ничего вообще не могу разобрать =(
Запросы из нескольких мест — это в плане передавать APIController (один из основных контроллеров приложения) ссылкой в контроллеры для того, чтобы они могли вызывать его request()? Т.е. так делать не годится?

etc
10.09.2010, 14:58
А зачем? Где такая ситуация может возникнуть? Максимум дочерний контроллер попросит основной загрузить что-нибудь. После загрузки все и так попадет в модель, поэтому и заниматься обработкой данных дочернему контроллеру никакого смысла нет, ему необходимо лишь наблюдать за моделью.

Zebestov
10.09.2010, 15:04
Вот именно тут я что-то не могу собраться вкучу.
Как именно контроллер запросит загрузку и у кого?
или даже так:
Кто и как зарегистрирует эту модель в APIController и кто и как будет просить данные для модели?

Сорри, если туплю ) надо разобраться.

etc
10.09.2010, 15:09
Дочерний контроллер просит основной загрузить данные. Тот в свою очередь дергает APIController и просит загрузить то-то. Он загружает, отдает основному полусырые данные. На основе оных основной контроллер заполняет модель. Дочерний контроллер слушает модель и видит там данные. Всё, процесс завершен.

Zebestov
10.09.2010, 15:35
На основе оных основной контроллер заполняет модель
Во! Вот это место.
Как основной контроллер знает, какую модель заполнять данными?
Все модели зарегистрированы в нем, или он получает ссылку на конкретную модель при запросе на загрузку от MenubarController?

etc
10.09.2010, 15:39
У него есть ссылки на все модели.

Zebestov
10.09.2010, 15:41
Так. А про какую модель идет речь сейчас — как узнает?

etc
10.09.2010, 15:48
Непосредственно по вызываемому методу. Нужно уйти от абстрактного запроса данных к совершенно конкретному. Если контроллер хочет данные по меню, то APIController должен составить соответствующий реквест и идентифицировать приходящие данные по нему же. При получении данных вызвать соответствующий метод основного контроллера (если таковой в нём есть).

Zebestov
10.09.2010, 16:18
ага. теперь понял. вроде.

APIController — большой класс для работы с разными API. Имеет метод request(query:String, ... args);

MainController — основной класс. Имеет среди прочих публичные методы loadMainMenu(), loadFriends(user_id:int), loadPhotos(album_id:int) и т.д. Каждый метод формирует правильный запрос и по факту загрузки сам раскидывает данные по заведомо определенным для каждого метода моделям.

MenubarController — контроллер основного меню, который в частности вызывает метод MainController#loadMainMenu(), который сам выложит данные в MenubarModel по факту загрузки.

так?

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

Zebestov
10.09.2010, 16:57
etc, спасибо! стало понятно, что я совсем не вкурил в само дерево проекта.

Если в диалоговом окне динамически создается список для выбора друзей. Мы во время выполнения создаем новые экземпляры контроллера, модели и вида.

Как я понимаю каждая ветвь (контроллеры, модели, виды) должна быть древовидной и расти с помощью чего-то наподобие addChild.

В частности аналогом stage для любого контроллера должен выступать mainController (чтобы мы могли запрашивать его).

Если так, то в самом начале mainController еще не знает о еще не созданном friendsListModel, который будет ждать данных, когда friendsListController вызовет mainController.loadFriends(user_id), потому что вся эта тройка будет создана (может быть) если пользователь выберет соотв. пункт меню.

Разумеется при добавлении (addChild) модели можно событиями сообщить наверх вплоть до mainController, что появился новый ребенок-модель. Но как mainController поймет, что с ним делать дальше? Ну что именно сюда мы будем передавать список друзей, а сюда — список фоток и т.д. Интерфейс?

etc
10.09.2010, 17:01
Список друзей принадлежит текущему пользователю. Изначально он пуст. Основной контроллер прекрасно знает о текущем пользователе и его списке друзей. Если запрашивается список друзей другого пользователя, то как минимум должен быть идентификатор этого пользователя в ответе, поэтому, опять же, нет проблемы взять нужного пользователя из модели и отдать ему друзей в основном контроллере.

Zebestov
10.09.2010, 17:24
Пример.
За все время приложение запросит следующие данные:

- список друзей некоего пользователя
- список альбомов пользователя
- список фотографий из альбома

значит все эти модели должны быть публичными свойствами mainController:


public var friendsModel:FriendsModel = new FriendsModel();
public var albumsModel:AlbumsModel = new AlbumsModel();
public var photosModel:PhotosMidel = new PhotosModel();


и когда дело дойдет до создания списка фотографий, то мы в контроллере диалогового окна someWindowController, который имеет свои model и view делаем так:


var somePhotosListView:ListView = new ListView(mainController.photosModel);
var somePhotosListController:ListController = new ListController(
mainController, // ссылка на основной контроллер
mainController.photosModel, // модель
this.somePhotosListView:ListView // вид
);

this.model.addChild(mainController.photosModel);
this.view.addChild(this.somePhotosListView);
this.addChild(somePhotosListController);


Ход мысли туда?

Добавлено через 2 минуты
Ну насчет публичных свойств в mainController я поспешил — достаточно дать доступ через get

etc
10.09.2010, 17:30
Нет, не туда.
Френды и прочая должны быть свойствами UserModel и создаваться сразу с ним. ListView получает линк на user.photos. Контроллер SomeWindowController имеет линк либо на user, либо весь model (хотя он ему и не нужен), у которого есть currentUser.

Zebestov
10.09.2010, 19:11
т.е. если переписать, то все модели должны быть свойствами mainModel:


public var friendsModel:FriendsModel = new FriendsModel();
public var albumsModel:AlbumsModel = new AlbumsModel();
public var photosModel:PhotosMidel = new PhotosModel();


someWindowController создаем так:


var someWindowController:ListController = new WindowController(
mainController, // ссылка на основной контроллер
mainModel, // ссылка на основной контроллер
someWindowModel,
someWindowView
);


т.е. окно всегда среди прочих параметров принимает еще и mainModel, потому что часто создает группы MVC, где модель — это что-то из списка первой троицы.

а уже конкретный список создаем так:


var somePhotosListView:ListView = new ListView(mainModel.photosModel);
var somePhotosListController:ListController = new ListController(
mainController, // ссылка на основной контроллер
mainModel.photosModel, // модель
this.somePhotosListView // вид
);

this.model.addChild(mainModel.photosModel); // и вот этого я так понимаю делать не надо?
this.view.addChild(this.somePhotosListView);
this.addChild(somePhotosListController);


теперь как?

etc
10.09.2010, 19:39
addChild не надо. И вообще, я не очень вкурил, где располагается последний код и что такое this.model почему это не mainModel.

Zebestov
10.09.2010, 19:42
последний код располагается в someWindowController в том месте, где надо создать в окне список друзей.
а почему не mainModel... эээ... я просто насмотрелся этой схемы: http://www.flasher.ru/forum/showpost.php?p=860254&postcount=2, а там модели "крепятся" к родителю, а не к корню. хотя этот момент мне не понятен в той схеме.

etc
10.09.2010, 19:46
Никуда они не крепятся, они связаны иерархической связью и все, при создании контроллеров остаются на месте. addChild одного элемента в две разных модели сделать нельзя.

Zebestov
10.09.2010, 19:51
понял.
etc, помощь была неоценимой, спасибо.
пойду пробовать.

Gaen
21.09.2010, 22:05
В этой теме затронут вопрос, с которым я давно не могу разобраться: как же все-таки делать иерархию mvc?

Из вышесказанного я смог выделить несколько мыслей:
1. Модель у нас одна, все слушают её и пишут в неё.
2. Иерархия модели аналогична иерархии DisplayList'а.

А что с контроллерами? Тоже ветвятся? Тогда откуда взялось обращение дочерних контроллеров к родительским? Кто кому на кого передает ссылки? Блин, это настолько непонятно, что я до сих пор не могу правильно сформулировать вопрос.

Допустим, есть игровое приложение, состоящее из двух больших кусков: "курилка", где можно создать игру либо присоединиться к существующей, и собственно сама игра.
Document Class создает главный контроллер и передает ему ссылку на себя же в качестве контейнера, этот контроллер создает модель, затем создает вид, передавая ему модель, и добавляет в контейнер. Главная триада up and running.
Теперь нужно добавить триаду, которая будет отвечать за курилку. Как это должно произойти? Как она должна быть связана с главной триадой?

Psycho Tiger
21.09.2010, 22:59
Document Class создает главный контроллер и передает ему ссылку на себя же в качестве контейнера, этот контроллер создает модель, затем создает вид, передавая ему модель, и добавляет в контейнер. Главная триада up and running.
Всё верно.
Теперь нужно добавить триаду, которая будет отвечать за курилку. Как это должно произойти? Как она должна быть связана с главной триадой?
Контроллер главный создаёт контроллер курилки. Он создаёт модель и вьюшку. Или главный контроллер создаёт всё трио - это не важно. Главное чтобы они все создались.

Главная модель имеет в себе ссылку на дочернюю модель (модель курилки). В главной вьюшке вложена вьюшка курилки. Контроллер главный, само собой, имеет ссылку на то что он сам создал - контроллер курилки. Когда из курилки выходят - курилка контроллер меняет курилку модель. Курилка модель в свою очередь сообщает об этом главной моделе (событием), главная модель от этого меняется. Главный контроллер, узнав о том что главная модель изменилась и говорит ему, что из курилки вышли - убивает курилку.

Gaen
22.09.2010, 14:52
Спасибо, вроде прояснилось.
Еще вопрос: каким образом из дочерней триады достучаться до родительской модели?
Сейчас у меня все устроено вот так:

/**
* Установка свойства. Если в качестве значения передать null, свойство удаляется.
* @param name - имя свойства
* @param value - значение
*/
public function setProperty(name:String, value:*){

//Запоминаем старое значение
var oldValue :* = this.data[name]?this.data[name]:null;

//Если новое значение такое же - ничего не делаем
if(value == oldValue) return;

//При получении null удаляем свойство
if(oldValue && (value == null)){

//Если это дочерняя модель - отписываемся от неё
if(oldValue is Model){

oldValue.removeEventListener(ModelChangeEvent.PROPERTY_CHANGE, this.dispatchEvent);

}//if

//Сносим
delete this.data[name];

}else{

//Устанавливаем значение
this.data[name] = value;

//Если это дочерняя модель - подписываемся на её события
if(value is Model){

value.addEventListener(ModelChangeEvent.PROPERTY_CHANGE, this.dispatchEvent);

}//if

}//if

//Сообщаем об изменении
this.dispatchEvent(new ModelChangeEvent(ModelChangeEvent.PROPERTY_CHANGE, name, oldValue, value));

}//setProperty


Т.е. если в качестве значения передать модель, то она автоматически начнет слушаться для всплывания событий. И если дочерняя модель получает ссылку на родительскую, то она начинает её слушать, и при любом изменении одной из них получается перполнение стека от событий, которыми они друг друга закидывают.
Пока сделал ссылку на родителя просто отдельным полем.

etc
22.09.2010, 16:47
В этой теме затронут вопрос, с которым я давно не могу разобраться: как же все-таки делать иерархию mvc?

Из вышесказанного я смог выделить несколько мыслей:
1. Модель у нас одна, все слушают её и пишут в неё.
2. Иерархия модели аналогична иерархии DisplayList'а.

А что с контроллерами? Тоже ветвятся? Тогда откуда взялось обращение дочерних контроллеров к родительским? Кто кому на кого передает ссылки? Блин, это настолько непонятно, что я до сих пор не могу правильно сформулировать вопрос.
У нас второй вариант. И контроллеры тоже ветвятся, но не как DisplayObject, а простой связью — более старший контроллер передает ссылку на себя младшему. Как правило, в конструкторе.


Допустим, есть игровое приложение, состоящее из двух больших кусков: "курилка", где можно создать игру либо присоединиться к существующей, и собственно сама игра.
Document Class создает главный контроллер и передает ему ссылку на себя же в качестве контейнера, этот контроллер создает модель, затем создает вид, передавая ему модель, и добавляет в контейнер. Главная триада up and running.
Теперь нужно добавить триаду, которая будет отвечать за курилку. Как это должно произойти? Как она должна быть связана с главной триадой?
Основной контроллер грохнет вид, контроллер и модель игры, создаст модель курилки (если она не живет с самого начала) и вид с контроллером курилки. Проще говоря, создает другую триаду. Основная триада максимум получает пользовательские события от дочерней. В случае, если игра оффлайн, то получает событие «Игра закончена», либо в случае онлайна — от сервера.

Добавлено через 3 минуты
Спасибо, вроде прояснилось.
Еще вопрос: каким образом из дочерней триады достучаться до родительской модели?
Я вот честно говоря совсем не вижу необходимости. Зачем оно? Как максимум, к родительской модели может обратится дочерний контроллер через ссылку у родительского контроллера.


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

Psycho Tiger
22.09.2010, 17:27
Основной контроллер грохнет вид, контроллер и модель игры, создаст модель курилки (если она не живет с самого начала) и вид с контроллером курилки. Проще говоря, создает другую триаду. Основная триада максимум получает пользовательские события от дочерней. В случае, если игра оффлайн, то получает событие «Игра закончена», либо в случае онлайна — от сервера.

То есть ты предлагаешь сделать главный контроллер по типу Facade (или близкий к нему)? Я так понял ты предлагаешь в главном контроллере переключаться между режимами игры, грохая старую и создавая (всё это если нужно, конечно) новые.

etc
22.09.2010, 17:28
То есть ты предлагаешь сделать главный контроллер по типу Facad (или близкий к нему)? Я так понял ты предлагаешь в главном контроллере переключаться между режимами игры, грохая старую и создавая (всё это если нужно, конечно) новые.

Да, я это и предлагаю.

Psycho Tiger
22.09.2010, 18:03
Мне не совсем понятно, откуда главный контроллер получает уведомления от дочерних. По той ссылке, что передается в конструктор?

Я делаю похоже, только у меня главная триада вбирает в себя всех детишек. Т.е. я никогда не грохаю главную модель и главную вьюшку, а событие "сменить режим игры" главный контроллер получает от главной модели, в которую это событие бабблится от дочерней.

etc
22.09.2010, 18:10
Мне не совсем понятно, откуда главный контроллер получает уведомления от дочерних. По той ссылке, что передается в конструктор?
Подпишется на события дочернего.

а событие "сменить режим игры" главный контроллер получает от главной модели, в которую это событие бабблится от дочерней.
Вообще-то должно быть наоборот. Менять или не менять режим игры — решает главный контроллер на основании, скажем, дочернего контроллера, но никак не модели. Можно и от модели, конечно, но не по событию «Сменить режим».

Psycho Tiger
22.09.2010, 18:44
Мм. У меня в главной модели есть свойство currentGame, например.
Дочерний контроллер решает, что он сворачивается, и меняет свою модель. Эта модель изменяясь сообщает модели выше (главной) что всё свернулось, и меняется currentGame (например, на "menu"). Главный контроллер слышит это и решает, что делать дальше. Чаще всего добавляет меню )

Чем такой подход плох?

etc
22.09.2010, 18:59
Тем, что основной контроллер не может быть несогласным со сменой режима игры. Проще говоря, у него нет контроля над текущим режимом игры.

Psycho Tiger
22.09.2010, 19:17
М, ну да, прав. Поэтому в принципе поток инфы через модель излишнее, спасибо.

dimarik
23.09.2010, 00:02
а событие "сменить режим игры" главный контроллер получает от главной модели, в которую это событие бабблится от дочерней.

У нас модель стала общаться с контроллером? Это нонсенс.

Контроллер получает уведомления от представлений и от внешней среды. Меняет модель. Модель оповещает представления. Сменить режим игры может контроллер, получив соответствующее уведомление от представления (пользователь жмет кнопку "Сменить режим игры") либо от внешнего источника (таймер сработал, пришло уведомление от сервера или еще что-нибудь знаковое случилось).

Правда, я разок сделал по-своему. Если модель не имела значения для определенной переменной, то диспатчила об этом событие. Событие подхватывал контроллер и говорил "Ах, %model_name%, у тебя нет того, что у тебя просят. Ща забацаем." Удобство было в том, что вьюхи, созданные в некотором количестве инициировали чтение геттера модели. Геттер им отвечал дефолтно и попутно сообщал контроллеру и том, что нужно бы сделать так, чтобы у меня появились чисто конкретные данные, on demand, как бе. Весь цинус в том, что пока вью реально не попросит, не нужно напрягать сетевые ресурсы качать мегабайты.

Вот. А реально я ничего нового не придумал. Этот паттерн умные GoFы давно придумали и назвали Proxy. Вспомни я про это, то сразу бы избавил модель от ненужной суеты.

Psycho Tiger
23.09.2010, 18:20
Понятно, поучительно, спасибо)

Только вот где то я читал, что теоретически контроллер может слушать чужую модель, где не вспомню. Такая практика действительно существует или автор статьи не был достаточно опытен?

Psycho Tiger
27.09.2010, 21:19
2) Можно написать отдельный контроллер модели, который работает с соединением и помещает приходящие данные в модель.
dimarik говорит что когда контроллер слушает модель - нонсенс, но ведь не через вьюшку сообщать контроллеру данные от модели...

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

Из самых "трезвых решений" в голове - как раз передавать контроллерам ссылку на коннектор, который испускал бы события по типам - LobbyEvent, GameEvent и т.д., соответственно каждая часть игры ловила бы только свои события. Но не знаю, насколько это правильно.

etc
27.09.2010, 21:28
dimarik говорит что когда контроллер слушает модель - нонсенс, но ведь не через вьюшку сообщать контроллеру данные от модели...
Непонятно только, как это относится к указанной цитате.


Вообще имеется проект с множеством подзон (курилка, сама игра, лобби и т.д.), и всем нужно иметь связь с сервером. Очевидно, что если и заводить одну модель, которую отдавать всем созданным контроллерам на прослушивание - нелогично, логичней отдавать ссылку на коннектор к серверу. Вообще как поступить?
Не на коннектор, а на основной контроллер, у которого можно подписаться на события/команды от сервера (они проходят сквозь него после обработки основным контроллером). Коннектор передать нельзя, т. к. клиент у него один — основной контроллер.

Psycho Tiger
27.09.2010, 21:43
Непонятно только, как это относится к указанной цитате.
Буфер обмена меня подвёл =)
Контроллер потенциально может слушать модель, т. к. он не единственный контроллер, который может её изменять.
Подумал. Димарик, наверно, имел ввиду что общаться с собственной моделью, на которую никто другой не подписан?

Не на коннектор, а на основной контроллер, у которого можно подписаться на события/команды от сервера (они проходят сквозь него после обработки основным контроллером). Коннектор передать нельзя, т. к. клиент у него один — основной контроллер.

То есть основной контроллер имеет логику парсинга сообщений от сервера до вида более менее удобном для дочерних контроллеров, после чего эти данные диспачатся от его имени - и кто успел, тот и съел?
Тогда:
1) Верно ли утверждение выше?
2) Насколько глубоко нужно делать парсинг? Прямо разжевать до вкуснятины, или достаточно минимальных действий - например, удалить служебную информацию у пакета (вроде его длины).
3) Не на коннектор, а на основной контроллер, у которого можно подписаться на события/команды от сервера (они проходят сквозь него после обработки основным контроллером).
(они проходят сквозь него после обработки основным контроллером) - сквозь что они проходят после обработки основным контроллером? Имеется ввиду конечный слушатель?

Коннектор передать нельзя, т. к. клиент у него один — основной контроллер.

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

etc
27.09.2010, 22:29
Подумал. Димарик, наверно, имел ввиду что общаться с собственной моделью, на которую никто другой не подписан?
Скорее эта модель более старшая по отношению к контроллеру.


То есть основной контроллер имеет логику парсинга сообщений от сервера до вида более менее удобном для дочерних контроллеров, после чего эти данные диспачатся от его имени - и кто успел, тот и съел?
Тогда:
1) Верно ли утверждение выше?
2) Насколько глубоко нужно делать парсинг? Прямо разжевать до вкуснятины, или достаточно минимальных действий - например, удалить служебную информацию у пакета (вроде его длины).
3)
(они проходят сквозь него после обработки основным контроллером) - сквозь что они проходят после обработки основным контроллером? Имеется ввиду конечный слушатель?
1) Нет;
2) Парсинг происходит в коннекторе, на выходе получается команда с аргументами;
3) После вызова метода с именем команды, например. Аргументы метода сохраняются для дальнейшей обработки другими контроллерами.



Не совсем понял что ты подразумеваешь под клиентом. Коннектор делается паттерном?
Как вижу я - коннектор после парсинга сообщения и определения принадлежности шлёт событие, если клиент - это слушатель этого события то не вижу преград подписать на него другие классы.
На манер LocalConnection#client/NetConnection#client. Без всяких событий.

Psycho Tiger
27.09.2010, 22:35
Арм... То есть самый главный контроллер, получает команду от коннектора с аргументами и дёргает соответствующие методы у дочерних контроллеров?

Как это реализуется? Динамическим доступом? Был бы очень рад минималистическому примеру :-[

etc
27.09.2010, 22:43
Арм... То есть самый главный контроллер, получает команду от коннектора с аргументами и дёргает соответствующие методы у дочерних контроллеров?

Как это реализуется? Динамическим доступом? Был бы очень рад минималистическому примеру :-[

Ничего он не дергает, он передает событие с привязанной командой всем желающим. Имя события составное, например command_enterAccount, где enterAccount — имя команды, он же метод основного контроллера (если есть).

Psycho Tiger
27.09.2010, 22:57
Так, проясняется.
Сюжет: пришло событие, что человек вошел на аккаунт. Коннектор распарсил его и сообщил как то это главному контроллеру (как? Событием?). Главный контроллер выстрелил событие, содержащее команду, которую подхватили все подписчики на это событие и начали делать то, что им следует делать.

etc
27.09.2010, 23:02
Так, проясняется.
Сюжет: пришло событие, что человек вошел на аккаунт. Коннектор распарсил его и сообщил как то это главному контроллеру (как? Событием?). Главный контроллер выстрелил событие, содержащее команду, которую подхватили все подписчики на это событие и начали делать то, что им следует делать.

Ещё раз стоит прочитать пост #156, особенно последнее предложение.

Psycho Tiger
27.09.2010, 23:08
Да, клиентом, здорово. То есть вызываем паблик метод, хорошо.
А как обращаться к коннектору от маленьких контроллеров? Ссылку на главный контроллер я тяну к дочерним, но тоже большим (например чтобы сказать главному контроллеру что действие закончилось, меняй курилку на игру), поэтому напрямую вызываю метод у главного контроллера, он дёргает коннектор.

UPD: на всякий спрошу, правильное ли у меня понимание клиентов: клиент - это объект, у которого приходящий запрос может дёрнуть какой-нибудь метод.

etc
27.09.2010, 23:20
Да, клиентом, здорово. То есть вызываем паблик метод, хорошо.
А как обращаться к коннектору от маленьких контроллеров?
Подписаться на событие типа CommandEvent, у которого будет ссылка на пришедшую команду.

Ссылку на главный контроллер я тяну к дочерним, но тоже большим (например чтобы сказать главному контроллеру что действие закончилось, меняй курилку на игру), поэтому напрямую вызываю метод у главного контроллера, он дёргает коннектор.
Можно и так, а можно оформить методом call, в котором первым аргументом идет имя отправляемой на сервер команды. Вариантов полно.

Psycho Tiger
27.09.2010, 23:41
Так. Резюме:
1) пришли данные. Например, враг сделал свой ход и новые координаты врага. Пришли они в коннектор, коннектор их переваривает.
2) После этого коннектор дёргает метод у главного контроллера. Тут логичен вопрос, в каком виде он это делает? На каждый тип действия свой метод (типа атаковали - один метод, написали в чат - другой, пошел дождь - третий)?
3) В главном контроллере испускается событие, что враг походил. Событие содержит новые координаты врага.
4) Контроллер врага, который имеет ссылку на главный контроллер слушал это событие и переместился.
5) Враг нанёс удар, контроллеру надо отправить это на сервер. Он используя ссылку на главный контроллер вызывает у него метод call с необходимыми параметрами. (когда я говорил "напрямую вызываю метод у главного контроллера, он дёргает коннектор" я имел ввиду что вызываю метод подобный call, где описываю всё что я хочу отослать).

Поправь пожалуйста, где на этот раз ошибся. И спасибо большое за помощь)

etc
28.09.2010, 12:22
1) Коннектор без понятия, что конкретно пришло, он распознает это всё как команду и только;
2) Вызывает moveEnemy(id, x, y), точнее (this._client[command.name] as Function).apply(this._client, command /* Command extends Array */);
3) Нет, событие идет new CommandEvent('command_' + command.name, ..., command). Его на самом деле отправляет коннектор после вызова команды у client, а контроллер тупо редиректит;
4) У врага контроллера нет, есть модель EnemyData, у неё тупо метод moveTo(x, y), его вызывает либо основной контроллер, либо дочерний, скажем, боевки;
5) Удары наносит сервер. Действия же игрока отправляются через основной контроллер, используя его метод call. Внутри call пришедшие аргументы перенаправляются в коннектор для отправки в виде команды на сервер.

Psycho Tiger
28.09.2010, 12:48
Ага, резюме 2.0:
1) Коннектору приходит пакет. Он видит, что это команда, отделяет имя команды от её аргументов, создаёт экземпляр класса Command. В _client он хранит ссылку на главный контроллер. У главного контроллера открыты методы для коннектора, имя метода совпадает с именем команды (или зная команду можно узнать имя метода).
2) Коннектор дёргает метод, сопоставленной этой команде у контроллера.
3) Коннектор испускает событие CommandEvent, которое главный контроллер редиспатчит, чтобы его поймали все кто хотят.
4) Понятно, а в случае чего-то мелкого, что требует взаимодействия с сервером, но содержащее контроллер - что слушает главный контроллер? Модель или контроллер? В каких случаях всё-таки слушает, а в каких контроллер старший вызывает методы напрямую?
5) Любой объект, который хочет общаться с сервером ловит ссылку на главный контроллер и дёргает его метод call.

У меня вопрос по пункту 2-3: зачем дёргать сначала метод у клиента, а потом слать через него событие? По сути можно обойтись одним событием, который главный контроллер схватит первым. Можно одним вызовом у клиента - клиент сам сделает событие.

etc
28.09.2010, 12:55
4) Ничего не слушает, ему по барабану в таком случае. Младший контроллер подпишется на конкретное событие CommandEvent и работает с пришедшим событием;
5) Только младшие контроллеры.

Событие не через метод шлется, а следующей строкой после вызова метода, в коннекторе.

Psycho Tiger
28.09.2010, 13:02
Событие не через метод шлется, а следующей строкой после вызова метода, в коннекторе.
Это я понял, но не понял зачем слать и событие и дёргать метод. В принципе можно обойтись или событием (контроллер схватит событие и сэмулирует запуск этого метода) или одним лишь вызовом метода (контроллер сам сделает событие). Зачем такое разделение? Я так понял что главный контроллер должен что-то сделать, а потом должны сделать все детишки, поэтому вот так. Но не понятна такая реализация;

4) Нет, плохо выразился:
Понятно, а в случае чего-то мелкого, что требует взаимодействия с сервером, но содержащее контроллер - что слушает главный контроллер? Модель или контроллер?
Я хотел спросить КТО слушает главный контроллер, т.е. кто подписывается на CommandEvent у главного контроллера - модель или младший контроллер. Но в твоём комментарии уже есть ответ, спасибо.

5) Хм, но чтобы передать в младшие контроллеры ссылку на главный - придется эту ссылку тянуть через промежуточные. Если связь с сервером нужна промежуточному контроллеру - можно ли ему воспользоваться этой ссылкой для связи с сервером или нужно отдавать это более мелким контроллерам? Что делать, если это проблемно или это совсем не задача мелких контроллеров?

etc
28.09.2010, 13:07
Это я понял, но не понял зачем слать и событие и дёргать метод. В принципе можно обойтись или событием (контроллер схватит событие и сэмулирует запуск этого метода) или одним лишь вызовом метода (контроллер сам сделает событие). Зачем такое разделение? Я так понял что главный контроллер должен что-то сделать, а потом должны сделать все детишки, поэтому вот так. Но не понятна такая реализация;
Для удобства, исключительно.

Я хотел спросить КТО слушает главный контроллер, т.е. кто подписывается на CommandEvent у главного контроллера - модель или младший контроллер. Но в твоём комментарии уже есть ответ, спасибо.
Модель вообще ни на какие чужие события не подписывается, в лучшем случае на события дочерних элементов.

5) Хм, но чтобы передать в младшие контроллеры ссылку на главный - придется эту ссылку тянуть через промежуточные. Если связь с сервером нужна промежуточному контроллеру - можно ли ему воспользоваться этой ссылкой для связи с сервером или нужно отдавать это более мелким контроллерам? Что делать, если это проблемно или это совсем не задача мелких контроллеров?
Да пусть передают более младшим, не криминал. Для них это будет базовый контроллер, а кто его им дал — они не знают.

Psycho Tiger
28.09.2010, 13:47
Спасибо большое, теперь всё стало понятно.
Только момент ещё в тумане - я правильно понял что call могут дёргать любые дочерние контроллеры по отношению к главному, но всё таки предпочтительнее если это будут крайне-младшие?

etc
28.09.2010, 13:50
Спасибо большое, теперь всё стало понятно.
Только момент ещё в тумане - я правильно понял что call могут дёргать любые дочерние контроллеры по отношению к главному, но всё таки предпочтительнее если это будут крайне-младшие?

Любые. На самом деле более одной вложенности контроллеров очень редко бывает. Например общее окно информации персонажа и его рюкзак. Есть контроллер всего окна, плюс два дочерних (хотя таковыми они не являются, т. к. могут работать и отдельно) — рюкзака и инфы. При желании основной контроллер может создать окно только с рюкзаком и подсунуть туда все тот же контроллер рюкзака.

Psycho Tiger
28.09.2010, 13:56
Ну почему же, базовый контроллер - контроллер игры, контроллер окна персонажа, в нём контроллер окна статов. =)

Спасибо большое, информация бесценна )

Psycho Tiger
02.10.2010, 21:29
Волей судьбы пишу клиент под игру, серверная часть которого уже написана (недобросовестный кодер пропал, предоставив половину исходников весьма низкого качества - взялся писать клиент с 0).
Соответственно возник такой вопрос:
1) Как таковых команд сервер не присылает. Он присылает какие-то идентификаторы, которые позволят идентифицировать, что же сервер хотел сказать. Соответственно клиентом главный контроллер назвать сложно - коннектор создаёт событие и дёргает метод onServerData главного контроллера и передаёт ему событие, которое главный контроллер и отдиспатчит. Это событие слушают дочерние контроллеры и при получении такового они определяют, им ли это сообщение адресовано. В итоге один из контроллеров признает его своим и парсит, остальные после раздумий игнорируют.

Правильно ли я понял теорию и применил на практике в моём конкретном случае?

Реализуя таким способом я не чувствую себя плохо из за того, что коннектор не дёргает методы клиента по каждому событию. Даже наоборот: мне кажется что на каждую команду от сервера излишне было бы создавать метод в главном контроллере - большая часть из них уйдёт дочерним (они получат его с события), остальная часть, которая должна дёрнуть метод клиента - как я понимаю, для управления элементами у которых нет контроллера (вроде примера с врагом). По моим соображениям таких элементов в игре скорее всего совсем не много, поэтому встают логичные вопросы:

2) Коннектор в любом случае дёрнет метод клиента (речь не про CommandEvent, а про вызов метода у клиента до), при любой команде от сервера, или же только в строго-определенных? Если главный контроллер ничего не должен делать - в таком случае: делается пустой метод, вызов обрамляется в try..catch или же у коннектора есть конкретные мозги чтобы понимать, на что нужно дёргать метод клиента, а на что ненужно?

3) В случае, если коннектор всегда дёргает метод клиента... то объясните, пожалуйста, почему. По мне если обработкой займутся дочерние контроллеры, то главному, в принципе, вмешиваться и не стоит.

dimarik
04.10.2010, 10:30
Мои рассуждения о доставке в нужный контроллер.

Можно распространять события по цепочке - chain of responsibility. Причем цепочка легко превращается в дерево, если следовать паттерну визуальных объектов. Если в первом (основном) контроллере нашелся нужный метод, контроллер делает event.stopImmediatlyPropagation(). Иначе событие передается дальше, к дочернему контроллеру посредством бабблига. Если он может такое событие обработать, то можно сделать следующее: либо event.stopImmediatlyPropagation(), либо event.preventDefault(). Во втором случае в основном контроллере можно понять, что событие не нашло адресата, проверив результат выполнения метода super.dispatchEvent() и как-то отреагировать. false означает что событие было захвачено, true - подходящий адресат не был найден.

Другой вопрос, оправдано ли ветвление контроллеров.

Psycho Tiger
04.10.2010, 11:20
dimarik, мысль ясна, спасибо. Я так понимаю если 2 дочерних контроллера, то событие отправляется в каждый. Только непонятно, как реагировать, если в обеих дочерних оно дошло до адресата )

P.S. сейчас вот пишу казино. Там есть общие окна для всех режимов игры (сама игра, зритель, курилка, лобби и т.д.), типа посмотреть информацию об игроке, отправить подарок, открыть окно привата и т.д.
Оно всё взаимодействует с сервером, конечно, поэтому без контроллера не обойтись. В итоге я вынес мозги этих общих действий в базовый контроллер, базовая вьюшка всегда находится в DisplayList, она же является host`ом (display object container`ом) для всех остальных вьюшек. Если надо открыть окно - событие просто бабблится по вьюшкам, а возле главной вьюшки её ловит главный контроллер. Главный контроллер создаёт так же другие контроллеры (например, контроллер лобби), который уже размышляет о том, о чем ему сделать, а когда нужно отправить что-то на сервер - монопольно дёргает call и vkontakteCall у главного контроллера (ну, что описал Дениска, в принципе). По моему в таких случаях ветвление контроллеров не то что оправдано, а даже очень удобно. Интересно выслушать твоё мнение по поводу такой системы.

Добавлено через 28 часов 12 минут
P.S. dimarik, твой подход доставки в нужный контроллер чудо ) Не думал что на практике это будет столь удобно, спасибо огромное.

3p.station
12.10.2010, 12:13
сам только начал вникать в эту тему (жаль что еще нету задач котороые имело бы смысл так реалиозвать)
вот нашел
такой вариант описания с минимальным примером (http://easyflash.org/flashlearn/flasharticles/752-pattern-proektirovaniya-model-view-controllermvc.html)

и еще рекомендуют многие

роботлегс (http://blog.diestro.ru/znakomstvo-s-robotlegs/)

Psycho Tiger
12.10.2010, 15:15
Вот честно, не смотрел и не очень хочу смотреть фреймворки подобного плана.
Паттерн на то и паттерн, что это просто описание "проблема"-"решение" в хорошем плане. Если речь об архитектурном паттерне - это решение проблемы нормальной архитектуры приложения. Но каждое приложение достаточно уникальное, чтобы заимствовать чужую архитектуру, ни одна написаная ранее архитектура не будет той гибкости, которой я хочу в данном приложении.

3p.station
12.10.2010, 15:45
если каждое приложение достаточно уникальное, то смысл тогда в MVC ?
если я верно понял, то этот паттерн для того чтобы эту уникальность и разрулить и например одну и туже модель исопльзовать не один раз и не в одном проекте, а следовательно она должна иметь какието "правила" котороые можно будет исопльзовать в дургом проекте и при этом не думать об переделвании интерфейсов и способов связывания между модулями
хотя это лишь мне так поудмалось

а вот по поводу той статьи что ниже я скинул, - вникнул и понял что там не то ):
там чел внизу про это и напаисал в комментах и дал ссылку на википедию (http://ru.wikipedia.org/wiki/MVC)

Psycho Tiger
12.10.2010, 16:04
Смысл MVC как раз в унифицированном решении проблемы архитектуры, когда требуется отделить данные от представления от манипуляции с этими данными. Ну вот проще говоря, не мыслю как паттерн можно под гребёнку смести, не говоря уж об архитектуре. Рассмотрим паттерн адаптер: он может служить единым интерфейсом для 2-3 социальных сетей, а может служить для единых входных данных от входных устройств - проще говоря управление мышкой/клавиатурой/джойстиком. Единственное что между ними общего - "единый интерфейс для работы с..." - но в этом и суть адаптера. Если смотреть со стороны MVC - общее это может быть некий абстрактный объект контроллера, модели и вьюхи, у которых расставлены эти связи между трио. Но эти связи во всех 3 классах дай бог нагребут 150-200 строчек кода. Я не вижу смысла ради 1% кода в проекте подстраивать под него остальные 99.
Описанное выше - конкретно моё имхо). Наверно, стоит пощупать эти фреймворки чтобы делать такие категоричные заявления... но как то не тянет.

3p.station
12.10.2010, 16:22
когда требуется отделить данные от представления от манипуляции с этими данными. вот эта отделенность как я понял для того чтобы можно было использовать любую часть в трио для других проектов, а следовательно должны быть какието "правила" их создания

вообщем если честно, еще гулбоко не вникал в роботлегс , как чего пойму отпишусь ( :

Psycho Tiger
12.10.2010, 16:35
Не совсем. В идеале для меня так:
Вьюшка - отображает. Очень удобно тем, что невозможно отображением подпортить логику игры. Добавил вспышку света при взрыве гранаты - и никак не может произойти так, что из за вспышки у врага на крыше упали штаны. Такие баги допустить очень легко, когда всё в куче. Ещё удобно тем, что разработку можно вести на уровне кружочки-квадратики и не ощущать скованность из за неполноты представления - добавляя отображение мы меняем 33% кода, вместо всей 100 (если представить что модель-контроллер-вьюшка имеют равный объем кода, что почти всегда неверно :D). Очень удобно когда ещё люди не знают, как будет выглядеть игра. Есть логика игры, а вот над представлением ещё думают, есть мелкий концепт. Чертовски удобно когда несколько видов игры - например вид сверху и вид сзади (3д, но игра функционала такого же как в 2д).

Модель - ну тут в идеале - полная информация о процессе. Идеальная модель для меня - это если удалить вьюшка и контроллер, а потом создать их снова чистенькие и отдать эту модель - всё восстановится в точности/почти в точности, как было раньше. Очень удобно для сериализации: если она не DisplayObject - то просто записываем в ByteArray - получаем AMF объект, который можем сохранить... да хоть в файл. Некоторые в качестве модели используют DisplayObject`ы, ради иерархии и бабблинга событий. Врать не буду - в целом идея удобная, а сериализовывать модели... ну лично мне не приходилось никогда. С другой стороны DisplayObject`ы едят больше памяти, чем просто EventDispatcher`ы, так что эти моменты весьма спорные. Но это я от темы отхожу.

Контроллер - ерунда которая всем этим делом управляет и содержит все мозги.

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

cleptoman
14.10.2010, 17:45
чуть не растерял остатки мозга, пока все страницы осилил.
понял одно: я не тру и отсталый недофлэшер)

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

раздает данные детям.
слушает детей на предмет запросов на обновления инфы.

если есть сервер, то как правило есть поставщик данных, который пуляет запросы и диспатчит события( если чтонить прилетает) в главный класс, в удобной для меня форме.

понимаю как-то далековат я от MVC

Psycho Tiger
14.10.2010, 18:10
Понимание и прелести MVC приходит со временем. Поначалу начинаешь сам отделять управление от отображения, потом начинается разделение ещё и на данные, помимо отображения и управления, ну а потом осознание что визуализируются то данные, и по сути управление к отображению имеет мало отношения. И тут мы приходим к MVC..)

-De-
14.10.2010, 21:47
Присоединяюсь к вопросу - зачем нужно MVC на флэше? Хочется простых ответов, на пальцах. Вопрос даже скорее "зачем отделять отображение (ака вьюху)", "что мне лично дало отделение вьюхи".
Вот критика (нубская и тролльская, конечно, просто считаю, что спрашивающий должен написать больше, чем отвечающий, т.к. ему это больше надо):
MVC делалось чуваками для серверных языков, чтоб при необходимости можно было легко сменить модель (база данных была в текстовичках, стала на оракл) и вьюху (можно сделать тонкий веп клиент (который там секьюрный и отовсюду доступен), можно толстый (который быстрее и мож чуток побольше умеет), можно розовый (для блондинок)). Соответственно, это достаточно большое и сложное приложение, у которого есть база данных и шанс, что клиенты будут значительно отличаться.
Ну т.е. флэш - это клиент, вьюха. Вьюха во вьюхе... ээ во вьюхе во вьюхе... Ну да, хорошо бы, чтобы можно было подменить данные (локализация, звуки, могу ещё расписать на пальцах выгоды), но это не MVC, это "отделяйте данные от кода", более старый в т.ч. принцип. Но смысл на флэше отделять вьюху?

Psycho Tiger
14.10.2010, 21:56
-De-, художники и дизайнеры ребята непредсказуемые. У игры есть концепт, геймдизайн и всё такое - её можно писать. Пишутся контроллеры и модели, которые впоследствии не трогаются, а весь маразм и гениальность художников воплощается лишь во вьюхе. Невозможно повредить логику игры неверными шагами - в этом прелесть. Количество багов на проектах с мвц лично у меня стремится к 0, как без него они достаточно частые, и ещё фиг пойми почему.

P.S. локализация и звуки это задачи сугубо вьюхи. к модели отношения не имеют.

Котяра
14.10.2010, 22:03
Тигра: ты вещаешь, прям как убелённый сединами гуру понявший истинную истину)))
но мвц - не панацея, - лишь один из способов. В реальных задачах даже ООП не всегда приемлем.
Но я не против МВЦ - это заразно))
Я против его использования везде и всегда и использования МВЦ- фрэймворков (хотя иногда и они полезны)

Psycho Tiger
14.10.2010, 22:07
@Котяра: просто начал уже более-менее разбираться. Объясняю чтобы проверить твёрдость моих теоретических знаний )

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

-De-
14.10.2010, 22:22
Ээ, картинки, звуки, анимации, ну т.е. ассеты - это данные.
Я не против MVC, просто я лично птица гордая, надо пнуть. И хрен бы со мной, но я ж (конечно же, какие сомнения) не для себя, думаю я не один такой. Для кармы там полезно обьяснить неразумным преимущества MVC, как отмазка от ментов может прокатить и пр. =)
ЗЫ: дикий оффтоп и вброс, но если у вас не меняется логика игры в процессе производства, то вы - не игродел %)

Psycho Tiger
14.10.2010, 22:33
Почему же, меняется, дорабатывается, добавляются новые плюшки. Но поменять картинку, добавить фейрверк и всё в этом роде - это происходит куда чаще.

Звуки, картинки, анимации - это не модель, в общем случае. Всё, что юзер видит на экране - это вьюшка. Модель хранит количество патронов в обойме, количество обойм и идентификационный номер автомата. Вьюшка берёт эти 3 числа и устраивает на экране... да хоть 2 мировую.

-De-
14.10.2010, 23:02
Да, возможно у меня в голове неправильное MVC, но для того MVC, что у меня в голове, я вон выше обьяснил, зачем оно нужно вообще.
А у вас выгоды не видно. Проверка на выгодность: меняем поведение автомата при том, что "количество патронов в обойме, количество обойм и идентификационный номер автомата" остается одним и тем же, меняем в одном месте, скорее всего простые и понятные штуки (интересно, кстати, какие например). Вроде ок. А если нет вьюшки, т.е. ваша модель берёт 3 числа и устраивает непристойности, то... то же самое! Зачем платить больше?
Т.е. есть вот автомат. Есть его какие-то данные, которые "одни для всех" - они модель. Они - на сервере вообще. Зачем флэшке об этом знать? Флэшка должна по этим данным данным свыше изобразить автомат. Если меняется характер этих данных (сплэш там добавляется например), то один хрен надо править флэшку. И хорошо бы, чтоб в минимальном числе мест. Если автомат становится супермеганавороченным классом, лазить по которому грозит похуданием, то есть куча других способов сгруппировать куски автомата по разным классам.

Psycho Tiger
14.10.2010, 23:37
Своё виденье я описал в посте №180 (http://www.flasher.ru/forum/showpost.php?p=942325&postcount=180).

-De-
15.10.2010, 01:38
Вьюшка - отображает. Очень удобно тем, что невозможно отображением подпортить логику игры.
Примеры? Были долго тупые бока, из-за того, что (в терминах MVC) вьюха меняла модель. Причем все отлично знали, что такое делать нельзя и из-за этого эти бока (а если бы думали, что "невозможно"?). Передача данных во вьюху только по значению - единственное, что спасло бы, но как-то оно не гибко. В MVC надо думать, что же добавить в модель + всё равно думать, какие действия на какие условия ты завязываешь, у меня давно отображение логику не портит (багов особо меньше из-за этого не стало, правда).

Ещё удобно тем, что разработку можно вести на уровне кружочки-квадратики и не ощущать скованность из за неполноты представления - добавляя отображение мы меняем 33% кода, вместо всей 100 (если представить что модель-контроллер-вьюшка имеют равный объем кода, что почти всегда неверно :D).

Не согласен насчёт обьёма кода, ведь собсно надо написать "рисуем такую-то штуку по таким-то данным", а где это писать - не так важно, в MVC ещё и потеряем из-за накладных на передачу данных. А на уровне кружочков работать можно и без MVC (лично знаю, работали).

Чертовски удобно когда несколько видов игры - например вид сверху и вид сзади (3д, но игра функционала такого же как в 2д).

Чем при MVC легче? "Рисуем сверху", "рисуем сзади" придется писать примерно одинаково, разрулить, когда как рисовать - никаких проблем.
Вот сохранять игру - да, без вариантов, MVC - то, что надо.
ЗЫ:Вообще мозги начали поворачиваться, спасибо.

КорДум
15.10.2010, 08:39
Как трудно уследить за всеми контроллерами? Если контроллеров куча, а это, я думаю, очень хорошо (конечно, если правильно структурировано). Ведь проследить, что там что куда посылает, если что-то там случилось, довольно трудно, разве нет? Плюс держать в голове, что же там у нас во вьюшке, а что у нас в контроллерах. Не говоря уже о том, что там у нас творится с данными в модели... Пока я вижу только одно удобство у MVC, как Тигер сказал, править нужно только вьюшку. Но мне не видится удобным, ибо в голове как-то сформировался синглтон, все действия объекта пишутся в классе этого объекта и взаимодействуют через статичные ссылки Main. Да, в теории может быть MVC и очень даже хорош. Но практика взрывает мозг.

Волгоградец
15.10.2010, 11:04
Блин, всю ветку не осилил, может было уже, но спрошу все равно... Как обрабатывать событие enterFrame? По идее логику должен обработать контроллер, передать в модель, а та в, свою очередь, во вьювер должна передать команду обновить экран. Как-то мне кажется это замороченным - гонять кучу данных по кругу. Да, вьювер может сам себя обновить, минуя контроллер и модель, но какой же это тогда MVC?

Psycho Tiger
15.10.2010, 13:54
Примеры? Были долго тупые бока, из-за того, что (в терминах MVC) вьюха меняла модель. Причем все отлично знали, что такое делать нельзя

Эээ... вьюха отображала то что видит игрок №1, потом зрителю захотелось увидеть где сидит противник - вьюха поменяла модель и зритель стал видеть что видит игрок №2.

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

В MVC надо думать, что же добавить в модель + всё равно думать, какие действия на какие условия ты завязываешь, у меня давно отображение логику не портит (багов особо меньше из-за этого не стало, правда).
MC+V?

Не согласен насчёт обьёма кода, ведь собсно надо написать "рисуем такую-то штуку по таким-то данным", а где это писать - не так важно, в MVC ещё и потеряем из-за накладных на передачу данных. А на уровне кружочков работать можно и без MVC (лично знаю, работали).
Можно и синглтон в качестве центральной логики использовать. Прелести MVC вылезают где то после полмегабайта "свежего" кода - т.е. кода, написанного только под этот проект. Кружочки-кругляшки я говорил абстрактно, имея ввиду что отображаем кое-как, а игра работает правильно.
Чем при MVC легче? "Рисуем сверху", "рисуем сзади" придется писать примерно одинаково, разрулить, когда как рисовать - никаких проблем.
Другой вопрос что пока ты делаешь вид сверху кто-то делает вид сбоку, опираясь на известный интерфейс моделей. Разруливать всегда хуже чем изначально избежать неудобств: делая вид сбоку я не хочу знать о том, как сделан вид сверху и откуда растут ноги, чтобы разрулить.
Но практика взрывает мозг.
Ты сам виноват, начав консультироваться сразу по композитным MVC)
По идее логику должен обработать контроллер, передать в модель, а та в, свою очередь, во вьювер должна передать команду обновить экран.
Не, модель не передаёт команд. Модель говорит о том, что изменилась - а вьювер сам принимает решение, стоит ли ему новые данные визуализировать или нет.
Как обрабатывать событие enterFrame?
enterFrame чего, вьюхи? Типа очки плавно возрастают с 0 до 500? Это заботы сугубо вьюхи, в модели было значение 0, потом сразу стало 500.
Если речь о нужде события enterFrame в контроллере - тот создаёт DisplayObject и хватает у него этот enterFrame. Композиция, короче.

Котяра
15.10.2010, 14:55
ну по энтерфрэйм/таймеру можно менять модель тоже (например xPos,yPos,zPos)
а во вью это отображать.
так у меня сделана одна 3D стрелялка.
вью в этом случае это viewport камеры, модель - это координаты 3D объектов.
делать каждый 3D объект вьюшкой нельзя. вернее они тоже вьюшки, но другого уровня - слушают например поле модели статус и исходя из него меняют свою текстуру/форму.
Но вообще в таком случае чистый мвц не очень подходит.

etc
15.10.2010, 15:48
Присоединяюсь к вопросу - зачем нужно MVC на флэше?

Делаем тупую игру, отображаем твое бабло в каждом из открываемых окошек. Пришла команда с сервера изменить кол-во бабла. В MVC проблемы нет, каждая вьюшка бабла сама отобразит новое значение, сколько бы их не отображалось на экране. В отсутствие оного пришлось бы искать все вьюшки бабла на экране и ставить новое значение. Это на пальцах если.

Волгоградец
15.10.2010, 16:30
Не, модель не передаёт команд. Модель говорит о том, что изменилась - а вьювер сам принимает решение, стоит ли ему новые данные визуализировать или нет.
Да, я это и имел ввиду. Скажем каждый кадр у меня куча партиклов рисуется. Т.е. контроллер считает позиции и должен их в модель передать, так (ну если это тру MVC)? Ну а модель диспатчит во вьювер эти новые позиции. Замороченно как-то.
Но вообще в таком случае чистый мвц не очень подходит.\
Вот. И это уже тогда не MVC получается - а просто архитектура. А так как во флэше все привязано к enterFrame - нужен ли вообще нам MVC?
P.S.: но это так - нубские мысли. Все равно у каждого свое видение паттернов.

etc
15.10.2010, 16:35
Вот. И это уже тогда не MVC получается - а просто архитектура. А так как во флэше все привязано к enterFrame - нужен ли вообще нам MVC?
P.S.: но это так - нубские мысли. Все равно у каждого свое видение паттернов.

ENTER_FRAME это просто периодическое событие. Не понимаю, каким образом оно нарушает MVC.

Bgg
15.10.2010, 17:02
По моему, как минимум в gamedev'е рано или поздно все равно приходишь к MVC. Как не крути, слишком уж удобно отделять представление от данных и всем этим управлять контроллером. Потому не вижу смысла насильно разбираться в паттерне, который видимо просто негде пока применять.

Zebestov
15.10.2010, 17:47
Много читал/спрашивал/планировал и пришел к выводу смещения мозгового центра из Controller в Model:

Model
Хранит статические данные, состояния и прочее. При поступлении команд на изменение реализует логику по изменению состояния, сообщает об изменениях.

View
Элемент с двойственным характером. С одной стороны он на свой лад отображает данные из модели и следит за актуальностью этого отображения.
С другой стороны еще реагирует на действия пользователя (как правило мышь, клавиатура). Но мышью можно кликнуть по кнопке, сменить состояние CB, сдвинуть ползунок, что там еще? Модель не должна в этом ковыряться, ей нужен четкий сигнал с конкретным значением конкретного свойства/состояния.

Controller
Самый тонкий элемент системы. Его задача принять сообщение от View, и на основании этого сигнала выдать простое и понятное сообщение. Например вместо "слайдер яркости в состоянии 80" модель уже получит "яркость 0.8". И поменяй я во View слайдер на числовое поле или CB — контроллер переписал и готово. А модель и не прознает.

Основная позиция: не Controller, а Model является мозгом системы.
К такой схеме я пришел на текущий момент. Ни на что не претендую и не против замечаний — мог что-то не учесть, что станет проблемой при таком подходе (хотя как бы изначально он именно таким и был у отцов-основателей)

Psycho Tiger
15.10.2010, 18:10
Мозгом системы является контроллер. Представь ситуацию: ты решаешь задачу и пишешь мысли в тетрадку, там её решаешь. Ты - контроллер, тетрадка - модель.

Скажем каждый кадр у меня куча партиклов рисуется. Т.е. контроллер считает позиции и должен их в модель передать, так (ну если это тру MVC)?
В общем случае контроллер примет решение, где образовать сгусток партиклов и по какой траектории они полетят. А просчетом каждой партиклы занимается вьюшка.

Котяра
15.10.2010, 18:24
2Zebestov
немного меня смущает подмена понятий модели и контроллера у тебя.
модель
При поступлении команд на изменение реализует логику по изменению состояния
и контроллер
и на основании этого сигнала выдать простое и понятное сообщение
модель не должна реализовывать логику - это прерогатива контроллера.
контроллер не выдаёт сообщений он явно меняет модель.

Zebestov
15.10.2010, 19:01
немного меня смущает подмена понятий модели и контроллера у тебя ... модель не должна реализовывать логику - это прерогатива контроллера.
Вопрос спорный, как видно из разных источников. Мне ближе реализация логики в модели, которая кому-то что-то выдает "на показать" (методы для View), от кого-то принимает инструкции "на поменять" (методы для Controller), и вещает в эфир об изменениях (для View, для родителя). А кто эти люди — не ее солдатское дело =)
Пока все стройно.

контроллер не выдаёт сообщений он явно меняет модель.
Согласен — не так выразился. Модель предоставляет публичные методы, контроллер их вызывает.

Psycho Tiger
15.10.2010, 19:46
Zebestov, на простых проектах с мвц у меня тоже кода в модели было больше. Когда приходит пора плотной работы с серверами и социальными апи - очень много кода образуется в контроллере.

Zebestov
15.10.2010, 21:00
Psycho Tiger, я сейчас переключился на игрострой, так что потренируюсь "на кошках" и проверю в бою свою позицию.
А соц. проект до поры отложен, так что тут пока ничего не отвечу, чтобы не балаболить. Может ты и прав — надо пробовать.

Котяра
15.10.2010, 21:10
да. мс вообще сложно разделить иногда. но в моих реализациях - моджель - это только данные и диспетчер изменений. всё. изменяет данные только контроллер. читать данные может виды и контроллер.
плохо что нельзя разделить доступы для геттеров и сеттеров модели, только через нэймспэйсы или интерфейсы, но это очень не удобно.
приходится в модели реализовывать по 2-м интерфейсам
IМodelReadable (только геттеры) и IModel (геттеры и сеттеры)
первый - для видов - второй для контроллеров. можно забить, но не кошерно..

Psycho Tiger
15.10.2010, 21:24
Котярка, а зачем и геттеры и сеттеры? Только для контроллера, а он может иметь полный доступ, т.е. без интерфейсов. Ну это имо )

Zebestov
15.10.2010, 21:42
Psycho Tiger, а как же View! Для него read-only интерфейс полезен.

Котяра
15.10.2010, 21:53
я пробовал запрещать видам доступ к модели, принимая только событийные данные, это не всегда удобно.
иногда по событию смены статуса, например, виду нужно прочитать другие данные модели, которые в событии не передаются.

Psycho Tiger
15.10.2010, 21:59
View да. Но Котяра говорил про 2 интерфейса - один для контроллера и я подметил, что в большинстве случаев он лишний.

Котяра
15.10.2010, 22:28
2Тигра -да насчёт интерфейса для контроллера ты частично прав. контроллер имеет полный доступ, но мне приходилось делать Action ( в соседней теме обсуждается), которые являются частью контроллера, т.е. могу т изменять модель - им в качестве праметра передавались частичные интерфейсы IModel.
например в контроллере у меня встречатся такой код:
this.addAction(new ChangeStatusAction(this /* as IController*/,
model /* as IStatusModel*/,
GameStatus.BET));
ChangeStatusAction - может использоваться в другом контроллере, он например проверяет некие флаги доступные в IStatusModel и меняет поле status у модели..
всё это очень частный случай, просто у меня есть больше 100 независимых казиношных игр с более-менее общим кодом (всё лежит в одном пакете кода), общая механика может быть похожей, но в некоторых нюансах отличаться.. поэтому приходиться быть очень гибким чтобы не использовать копипасту, а использовать ООП.

Psycho Tiger
15.10.2010, 22:31
Угумс, согласен.
Знаю, что код выдернут из контекста но... ты вроде ведь не пишешь this и super?

Котяра
15.10.2010, 22:34
код написал прям здесь - this не пишу, это для здесь - как указание, что это метод контроллера

i.o.
16.10.2010, 05:57
Котяра, на мой взгляд тоже: с двумя интерфейсами - перебор. Вот можно сделать так (через нэймспейсы):
Model.as

package
{
public class Model
{
public function Model()
{
super();
}



protected namespace _nsSetter;

protected var _myProperty:String;



public function getNsSetter( controller:IController ):Namespace
{
if( !controller )
return null;

return _nsSetter;
}


public function get myProperty():String
{
trace( "get myProperty" );

return _myProperty;
}
_nsSetter function set myProperty( val:String ):void
{
trace( "set myProperty" );

if( val == _myProperty )
return;

_myProperty = val;
}

}
}

А в контроллере, для примера, что-то вроде:

var m:Model = new Model();
var nsSetter:Namespace = m.getNsSetter(this);

m.myProperty; // read
m.nsSetter::myProperty = "lalala"; // write


В getNsSetter( controller:IController ) - IController для примера. Можно и не для контроллера сделать.

Или вообще переменной _myProperty назначить не protected, а сразу _nsSetter нэймспейс. А сеттер myProperty и вовсе убрать. Тогда в контроллере нужно будет работать через неймспейс с переменной, а в остальных классах - только с геттером.

MrPoma
23.10.2010, 18:16
Растолкуйте ситуцию с главными и подчиненными контроллерами. Полагаю, что главный агрегирует подчиненный. Как у них общение налажено? Особенно интересует от подчиненного к главному.

etc
23.10.2010, 18:32
У подчиненного есть ссылка на базовый.

3p.station
23.10.2010, 22:21
соори что влажу сюда с нубским вопросом.
хочу, чтобы лучше разобраться, сделать галлерею используя мвц. модель должна сказать вьюхе путь кпревьюхам картинок, та должна грузить превьюшки фоток, а также реагировать на нажатие-выбор картинки из превюшек, и передавать контроллеру чтобы тот в свою очередь передал модели какую картинку выбрали, модель смотрит какая именно это будет картинкаи передает контроллеру чтобы он передал вью какую грузить ? так ?

Котяра
24.10.2010, 01:32
соори что влажу сюда с нубским вопросом.
хочу, чтобы лучше разобраться, сделать галлерею используя мвц. модель должна сказать вьюхе путь кпревьюхам картинок, та должна грузить превьюшки фоток, а также реагировать на нажатие-выбор картинки из превюшек, и передавать контроллеру чтобы тот в свою очередь передал модели какую картинку выбрали, модель смотрит какая именно это будет картинкаи передает контроллеру чтобы он передал вью какую грузить ? так ?
полная каша. почитайте сначала топик с начала и вдумчиво.

Psycho Tiger
24.10.2010, 14:20
соори что влажу сюда с нубским вопросом.
хочу, чтобы лучше разобраться, сделать галлерею используя мвц. модель должна сказать вьюхе путь кпревьюхам картинок, та должна грузить превьюшки фоток, а также реагировать на нажатие-выбор картинки из превюшек, и передавать контроллеру чтобы тот в свою очередь передал модели какую картинку выбрали, модель смотрит какая именно это будет картинкаи передает контроллеру чтобы он передал вью какую грузить ? так ?
Думаю статейку накатать на днях про MVC для нубов вот...

3p.station
24.10.2010, 14:31
нубы будут очень благодарны! и еще бы с примером какимто простым

MrPoma
24.10.2010, 21:05
Лучше с непростым. С простым там всегда все просто и понятно. Так что нужно с жизненным :-)

Psycho Tiger
24.10.2010, 21:15
От простого - к сложному. Думаю на днях накалякаю. Хочу с картинками )

dimarik
25.10.2010, 03:09
я пробовал запрещать видам доступ к модели, принимая только событийные данные, это не всегда удобно.
иногда по событию смены статуса, например, виду нужно прочитать другие данные модели, которые в событии не передаются.

Это общий дуализм GOF-паттерна Observer. По моему мнению, разработчику необходимо решить какое количество информации необходимо нести в конкретном событии. Можно ввести отдельное событие для каждого изменения модели. Можно ввести одно событие для любого изменения модели. Представление может запросить у модели (POP-операция) недостающие в событии данные. Событие может нести в представление избыточное количество информации (PUSH-система). Истина где-то рядом.

AlexDesinger
25.10.2010, 11:12
Думаю статейку накатать на днях про MVC для нубов вот...
да, да, скорее бы )))

Народ, а есть ли смысл использовать mvc для простых проектов, например, для создания flv плеера? Если смысла нет, может можно применить просто C+V?

i.o.
25.10.2010, 11:26
паттерны были придуманы для больших / сложных проектов. Если ваш плеер будет описан парой сотен строк кода, то использование mvc, на мой взгляд, неоправдано.

Psycho Tiger
26.10.2010, 19:59
да, да, скорее бы )))

Я кстати, её уже пишу.

Народ, а есть ли смысл использовать mvc для простых проектов, например, для создания flv плеера? Если смысла нет, может можно применить просто C+V?
MVC всегда есть смысл использовать, ровно как всегда есть смысл его не использовать.

Mur4ik
27.10.2010, 01:51
паттерны были придуманы для больших / сложных проектов. Если ваш плеер будет описан парой сотен строк кода, то использование mvc, на мой взгляд, неоправдано.

Паттерны бывают разные, и не все они только для больших и сложных проектов (и уж тем более не для них придуманы ;) ).
Если flv плеер планируется усовершенствовать и наращивать функционал (обычно так и бывает), то лучше изначально об этом подумать.

i.o.
27.10.2010, 02:29
Если flv плеер планируется усовершенствовать и наращивать функционал (обычно так и бывает), то лучше изначально об этом подумать.
Именно это я и хотел сказать. Спасибо )

Котяра
27.10.2010, 13:07
Это общий дуализм GOF-паттерна Observer. По моему мнению, разработчику необходимо решить какое количество информации необходимо нести в конкретном событии. Можно ввести отдельное событие для каждого изменения модели. Можно ввести одно событие для любого изменения модели. Представление может запросить у модели (POP-операция) недостающие в событии данные. Событие может нести в представление избыточное количество информации (PUSH-система). Истина где-то рядом.
Ну я про то же, моя цитата - обоснование использования readOnly интерфейса модели.
В случаях, когда вид должен читать данные модели (POP) - ссылка на модель должна передаваться виду как readOnly интерфейс.

Psycho Tiger
27.10.2010, 16:24
Вот вы говорите про pop и push от вьюхи в модель. Речь идёт о стэке? Разве это нормально что вьюшка так или иначе меняет модель?

Котяра
27.10.2010, 17:45
Вот вы говорите про pop и push от вьюхи в модель. Речь идёт о стэке? Разве это нормально что вьюшка так или иначе меняет модель?
Не, это не о том..
Pop Pull - система оповещения - берём данные самостоятельно.
Push - посылаем вместе с событием.
вот тут на примере java (http://www.eaipatterns.com/ObserverJmsExample.html)

AlexDesinger
27.10.2010, 18:14
Если flv плеер планируется усовершенствовать и наращивать функционал (обычно так и бывает), то лучше изначально об этом подумать.
угу, планируется, именно поэтому я и задумался о mvc

Psycho Tiger
27.10.2010, 19:33
Не, это не о том..
Pop Pull - система оповещения - берём данные самостоятельно.
Push - посылаем вместе с событием.
вот тут на примере java (http://www.eaipatterns.com/ObserverJmsExample.html)
А, всё, понял. Пример даже излишен, объяснения хватает заглаза ) Спасибо.
Только вот:
Представление может запросить у модели (POP-операция) недостающие в событии данные.
Всё таки pop или pull?

dimarik
27.10.2010, 20:44
Ошибся. Правильно pull. Спасибо что поправили.

cleptoman
29.10.2010, 18:08
ребят, пытаюсь повернуть мозги в сторону MVC, накидал кое-какой примерчик.
чего хотел - сделать возможность на ходу менять вьюшки деталей робота без особого вреда для здоровья (setter/getter). наказякал по этому случаю класс Robot.
вопрос - насколько тут все криво?

сорсы (http://cleptoman.ru/mvc/mvc.zip)
пощупать (http://cleptoman.ru/mvc/index.html)

Kidd002
29.10.2010, 19:19
cleptoman:
1. На мой взгляд стоит класс Robot сделать вьюшкой-наследником Sprite, а управление с изменением модели выделить из Main (WASD) и Robot(мышка О_о) в отдельный класс-контроллер. А то у вас получается что Robot выполняет функции и представления, и контроллера.

2. Не уверен что параметр moving в TracksModel - настолько важная информация, чтобы хранить ее в модели.

3. Ну и SPEED лучше хранить в модели (RobotModel или TracksModel)

cleptoman
31.10.2010, 21:47
спасибо, буду дальше репу морщить.

terbooter
22.11.2010, 10:38
Назрел такой вопрос.
Кто создает контроллеры?

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

Инстанцировать контроллер во вьюшке нельзя, тк 1) контроллер нужно инициализовать (передать ссылки на необходимые сабжекты), 2) неправильный расход ресурсов.

Значит ссылки на необходимые контроллеры должны передаваться при инициализации вьюшки.

Вопрос. Где и как создавать контроллеры?

Psycho Tiger
22.11.2010, 17:08
Кто создает контроллеры?
Контроллеры.
Рутовый класс создает главный контроллер, который создает модель (у меня модель создается полностью) и вьюшку (отдельные элементы у меня создаются по необходимости)
Вполне нормально )
Модель не имеет ссылок ни на контроллеры ни на вьюшку, только диспатчит сигналы
Аха.
Вьюшка получает ссылку на модель и строится по паттерну компановщик.
Необязательно. Вьюшка строится по паттерну Composite только из за того, что так устроен ФП (компоновщик = Composite? Я перевод плохо знаю )), а так MVC по бОльшему счету привязан только к обсерверу.
Инстанцировать контроллер во вьюшке нельзя, тк 1) контроллер нужно инициализовать (передать ссылки на необходимые сабжекты), 2) неправильный расход ресурсов.
Вьюшка - отображает. У неё едва мозгов на это хватает, куда ей контроллеры? )
Значит ссылки на необходимые контроллеры должны передаваться при инициализации вьюшки.
У вьюшки только одна ссылка - на модель.
Вопрос. Где и как создавать контроллеры?
В контроллерах. Контроллер создаёт модель и вьюшку. А может создать ещё один контроллер, который тоже создаст и модель, и вьюшку. Чаще всего он же передаёт младшему контроллеру ссылку на себя - чтобы тот мог подёргать у него некоторые методы)

Dukobpa3
31.12.2010, 13:46
Наконец-то осилил... Нафлудили мама не горюй:)

С простейшим примером вроде разобрался.

1. Есть главнй класс приложения.
2. Он создает главный контроллер себя отдает этому контроллеру ссылкой в качестве контейнера вьюх
3. Главный контроллер делает главную вьюху и пихает ее в этот контейнер
4. Главный контроллер делает главную модель (главная модель по сути хранит в себе текущий стейт и знает какое сейчас окно открыто + игровая доп-инфа по типу - сколько уровней пройдено, какой уровень следующий и т.п.)
//********************
после этих действий можно считать что мы стартонули.

Далее
0. У главной модели есть какой-то стейт по-умолчанию (майн-меню к примеру)
1. Главный контроллер глядит что у нас там в модели за стейт, в зависимости от этого создает триаду нужного экрана (майн меню, игровой экран, хайскоры, etc). Вьюху от этой триады засовывает в подчинение главной вьюхе, сам же подписывается на контроллер окна.
2. Вьюха этого окна диспатчит события на действия пользователя, события эти получает и обрабатывает контроллер окна.
3. Как только контроллер окна получает от вьюхи событие ченж_стейт - он диспатчит его дальше.
4. Ченж_стейт от контроллера окна получает главный контроллер. В ответ на это событие он зашибает эту триаду окна и создает другие (например были в главном меню и перешли в окно хайскоров, зашибли майнменю, и создали триаду хайскоров)
//*******************
Так, собственно с логикой Главного контроллера вроде разобрались. Он у нас такой типа крутой, по мелочам не разменивается и решает только глобальные вопросы (в данном примере только ченж_стейт)

Если я тут нигде не протупил - то поидее всё понятно, если же протупил то поправьте. А вопросы у меня дальше.

А теперь собственно самое интересное.
Мы заходим в игровой экран. А тут всё интересно. Возьмем по минимуму:
Делаем тавердефенс. Три вида башен. Пять видов врагов. Три уровня. Всё.

1. После того как главный контроллер получает событие смены стейта на игровой экран он убивает текущий экран и создает игровой (он в момент смены стейта уже знает какой уровень надо открыть, заранее запрашивая себе "правильную модель" с сервера или из файла или откуда там надо.)
2. Получает он данные из этого некого места, пихает их в свежесозданную модель. Прикручивает к ней ее персональный контроллер. Создает по этой модели вьюху и пихает эту вьюху в главную вьюху.
(получается с такой структурой задачей основного класса является только стартонуть это всё а потом быть контейнером для главной вьюхи. Главная вьюха является родительской для всех остальных.)

Тут пока вопросов вроде нету. Мы просто взяли и нарисовали уровень по той же схеме что и остальные окна.

Но в определенный момент у нас начинают появляться на уровне враги. Мы начинаем строить башни. Начинается рубилово-мочилово.
А вот здесь я в ступоре (хотя хз, сейчас напишу как я понимаю, а вы поправите, если бред)

1. По клику на "Создать башню №1" - вьюха уровня диспатчит событие "Создать башню"
2. Ее слышит контроллер уровня.
3. В ответ он создает триаду новой инстанции башни. Вьюху кидает внутрь вьюхи уровня. Модель хранит у себя. Контроллеру башни позволяет заниматься логикой башни(ну к примеру в контроллере башни всякие там таймеры и тригеры типа раз в 1 сек перезарядка, а если враг ближе чем 50 пкс - то стрелять)
3.1. ну и дальше башня живет своей жизнью.
3.2. Контроллеру уровня на башню пофигу пока она(либо ее модель, если обнаружит что хп==0; либо вьюха, если юзер тыкнет в кнопку "под снос") не задиспатчит что-то типа "Меня поламали".
3.3. Но на всякий случай контроллер уровня башню слушает, потому что может быть получено какое-то событие типа "на меня навели мышкой" при этом контроллер уровня должен отобразить над башенкой окошко с доп-инфой (или этот функционал висит на контроллере + вью башни? Если так то схема получается следующая - вьюха понимает что на нее навели мышью, никуда ничего не диспатчит и сама на себе выводит окошко инфы.)
4. когда контроллер уровня получает от башни заветное "Меня поламали" - он сносит триаду этой башни. Если надо, вносит в какой-то реестр разбитых башен - т.е. в модель уровня. Ну малоли, хайскоры от этого будут зависеть или еще чего.

Примерно так же дело обстоит и с врагами, с той лишь разницей что создание триады каждого врага делается не по клику "создать башню(врагов)" (хотя и так бывает), а по таймеру.

//**********************
Вот примерно так я себе это вижу.

А теперь вопорсы:
1. Что-то мне подсказывает что я слишком наворотил со вьюхами. В чем роль этого контейнера вьюх? А то у меня получилось что этот контейнер вьюх держит в себе только одну вьюху - главную. Тут короче где-то дублирование. Или я суть главной вьюхи не уловил, или же суть главного класса.
2. Ну и вот это всплывающее окошко - кто его показать должен? Вьюха башни или вьюха уровня? Насколько я понимаю то вьюха башни это какой-то спрайт или Мувик с анимацией самой башни. Стоит себе, привязана к координатам. Ну а чтоб это окошко выглядело так как охота чтоб оно выглядело - то надо его показывать в дисплейОбъекте уровня (ну чтоб за мышкой двигалось и в таком духе).
2.1. Хотя как вариант можно сделать отдельную триаду для хинтов. Триада эта будет на том же уровне что и триады башен с врагами. Т.е. в подчинении контроллера уровня. И тогда получится что контроллер башни получает от вьюхи башни "На_Меня_навели_мышкой", чешет затылок, ибо не знает что с этим делать, и диспатчит дальше. Контроллер уровня получает это событие, дергает контроллер хинтов "слышь чувак, а покажи как мне хинт для вот этой башенки" и все довольны.

//**********************

Короче моск пухнет уже, жду ответов:) Спасибо)

Добавлено через 30 минут
Перечитал еще раз.

У меня тут видимо слегка путаница с общением между родительским контроллером и детьми.

Когда я писал то подразумевал что родительский контроллер общается сугубо с контроллером ребенка посредством подписки на его события. И влияет на детей сугубо через контроллер. Ни к вьюхам ни к моделям детей напрямую не вмешивается.

Dukobpa3
31.12.2010, 15:48
Да)) в довершение ко всему меня интересует наследование.
Простейший пример. Есть какой-то шаблонный клас юнита. От него наследуются все остальные юниты. Если делать "Как обычно" - то получится что-то вроде:
25730

А если делать чтоб всё по правильно-мвцшному, то видимо что-то примерно такое?:
25731
Ну не без того что к примеру каких-то две модели у нас окажутся идентичными, то получится "сэкономить" на классах (хотя тут уже впору будет задуматься, а стоило ли разбивать на разные классы вместо того чтобы сделать одну триаду "юнит", а в нем просто unit.type = (1 || 2 || 3) ).

Я прав насчет второй диаграммы?

З.Ы. Пунктир - "наследует"; Стрелка с ромбиком - "Содержит в себе".

Kidd002
02.01.2011, 03:27
То что ты хочешь сделать - это не простейший пример. Нужно будет много раз переделывать чтобы реализовать все эффективно. Но если есть время и желание - то ОК.
По поводу описания:
Первое что бросается в глаза это то, что у тебя модель имеет какую-то декоративную функцию.
Я придерживаюсь этой схемы:
http://upload.wikimedia.org/wikipedia/commons/thumb/b/b5/ModelViewControllerDiagram2.svg/500px-ModelViewControllerDiagram2.svg.png
В ответ он создает триаду новой инстанции башни. Вьюху кидает внутрь вьюхи уровня. Модель хранит у себя.
Зачем контроллеру хранить модель у себя? Пусть он поместит ее в модель уровня.
Затем на диаграммах показано что вьюшки не имеют ссылки на модель. Да, можно заставить модель и представление общаться через контроллер, но здесь пусть лучше вьюшки знают что они отображают. Тогда если модель изменится - вьюшка сразу об этом узнает и обновится.
Далее: вьюшки могут создавать не только контроллеры. Можно сделать так, чтобы вьюшка уровня слушала свою модель на предмет добавления/удаления моделей башен и сама добавляла/удаляла себе соответствующую вьюшку. Контроллер уровня может поступать так же с контроллерами башен.
На второй диаграмме ты зачем-то дублируешь параметры moveable и size. Но ведь раз и контроллер, и представление имеют ссылки на модель, то они всегда могут получить эти параметры из нее.
По вопросам:
1. Что-то мне подсказывает что я слишком наворотил со вьюхами. В чем роль этого контейнера вьюх? А то у меня получилось что этот контейнер вьюх держит в себе только одну вьюху - главную. Тут короче где-то дублирование. Или я суть главной вьюхи не уловил, или же суть главного класса.
В твоем случае главная вьюха действительно не нужна. Пусть ее роль выполняет главный класс.
2. Ну и вот это всплывающее окошко - кто его показать должен? Вьюха башни или вьюха уровня? Насколько я понимаю то вьюха башни это какой-то спрайт или Мувик с анимацией самой башни. Стоит себе, привязана к координатам. Ну а чтоб это окошко выглядело так как охота чтоб оно выглядело - то надо его показывать в дисплейОбъекте уровня (ну чтоб за мышкой двигалось и в таком духе).
Всплывающее окошко ни вьюха башни, ни вьюха уровня отображать не должны. Ты забыл об интерфейсе. И вьюха уровня, и всяческие панельки должны иметь определенного родителя. Вот он и должен это делать.
2.1. Хотя как вариант можно сделать отдельную триаду для хинтов. Триада эта будет на том же уровне что и триады башен с врагами. Т.е. в подчинении контроллера уровня. И тогда получится что контроллер башни получает от вьюхи башни "На_Меня_навели_мышкой", чешет затылок, ибо не знает что с этим делать, и диспатчит дальше. Контроллер уровня получает это событие, дергает контроллер хинтов "слышь чувак, а покажи как мне хинт для вот этой башенки" и все довольны.
Зачем делать триаду для хинтов? Например хинт отображает информацию о башне. У башни есть модель, в которой она полностью описана. Так пусть моделью хинта будет модель башни.
Контроллер интерфейса (контроллер хинтов или сразу вьюшка интерфейса) получает событие от какой-нибудь вьюшки "на меня навели", смотрит какая у этой вьюшки модель (если она вообще есть), создает соответствующий хинт, дает ему модель этой вьюшки и засовывает хинт в вьюшку интерфейса. Как-то так.

Dukobpa3
02.01.2011, 19:19
То что ты хочешь сделать - это не простейший пример.
Имелся в виду простейший пример который не ограничивается какой-то парой тройкой триад, а уже что-то более похожее на полноценное приложение.

По поводу описания:
Первое что бросается в глаза это то, что у тебя модель имеет какую-то декоративную функцию.
Ну для меня модель - это сугубо база данных.
Контроллер - AI, калькулятор. Вью - морда, а модель - БД. Для того чтобы узнать в каком месте рисоваться - вьюха спрашивает координаты у модели. Для того чтобы получить операнды для расчетов логики - контроллер спрашивает данные у модели.
Исходя из этого модель не имеет публичных методов (в том числе и протектед) а имеет только пачку геттеров-сеттеров. Контроллер видит и то и то, а вью только геттеры. Плюс в каждом сеттере висит dispathEvent("changed param #xxx") - который слышат все желающие, и все кто от этого зависят - подстраиваются. Например контролер поменял координаты башни, модель отмаячилась, а вьюха услышала об этом и перерисовалась.

Зачем контроллеру хранить модель у себя? Пусть он поместит ее в модель уровня.
Принципиальной разницы не вижу. Ссылка на модель все-равно имеется. Если я помещу модель в модель уровня, то будет дублирование в некоторых моментах привносящее удобство, возможно.

Затем на диаграммах показано что вьюшки не имеют ссылки на модель.
Я просто упустил эту ссылку дабы не усложнять схему. Но да, ссылка есть, как минимум вью должна слушать события модели, а так же иметь доступ к геттерам модели.

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

На второй диаграмме ты зачем-то дублируешь параметры moveable и size. Но ведь раз и контроллер, и представление имеют ссылки на модель, то они всегда могут получить эти параметры из нее.
Просто копипаста из первого варианта схемы. На параметры не обращайте внимания. Всё что там нужно было увидеть, это квадратики и наследование между класса "Mxx", "Vxx", "Cxx".

В твоем случае главная вьюха действительно не нужна. Пусть ее роль выполняет главный класс.
Видимо да. А когда она будет нужна, в таком случае? Можно пример?

Всплывающее окошко ни вьюха башни, ни вьюха уровня отображать не должны. Ты забыл об интерфейсе. И вьюха уровня, и всяческие панельки должны иметь определенного родителя. Вот он и должен это делать.
Хм. наверное таки да. Я упустил триаду окна.
будет наверное так в итоге:
- Триада окна
-- триада уровня
-- триада интерфейса
-- триада доп-элементов(возможно и без нее)

Так пусть моделью хинта будет модель башни.
Это кстати да. Я так же упустил что можно клонировать нужные модели, или же вообще передавать существующие ссылки.

Спасибо за ответы.

Добавлено через 49 минут
помедитировал на "типовую схемку из википедии".

- Контролер содержит в себе модель и вью.
- вью содержит в себе модель.
- контроллер слушает вью.
- вью слушает модель.

т.е. касательно башни это будет выглядеть примерно так:
- V: "контроллер, Враг на горизонте"
- C: "вьюха, взять на прицел, заряжааай!!!"
- V: "Заряжаю"
- V: "Контроллер, Заряжено!"
- C: "Вьха, Огонь! Модель, у нас минус снаряд."

Вторая ситуация:
- V: "Ахренеть, нас враги атакуют"
- C: "Модель, делай минус 10 хп
- M: "Сделано, осталось 90%
- V: "Поняла, рисую анимацию потерпания от ударов".
......
- V: "Контроллер, они до сих пор атакауют"
- C: "Модель, делай минус 10 хп
- M: "Сделано, осталось 60%
- V: "Поняла, рисую анимацию пожара".
......
- V: "Контроллер, а они еще атакауют"
- C: "Модель, делай минус 10 хп
- M: "А хрен вам, овердамадж получили. Нету у нас больше хп"
- V: "Поняла, взрываемся. Контроллер, слышь, чувак, взорвались мы".
- C: "Товарищ Майор, мы взорвались"
- ParentC: "МодельУровня, делай минус башню. ВьюУровня - убери мусор"

//****************
Пральна я понимаю? Просто охота уже разобраться чтоб сразу и навсегда. Потому могу флудить глупыми вопросами.

terbooter
02.01.2011, 23:04
А почему у вас вьюха определяет что ее бъют?

Добавлено через 10 минут
Применительно к вашему примеру игры жанра TD, я бы построил архитектуру так:
Есть модель (не один класс, а пакет), в которой все происходит, что должно происходить на экране,
только виртуально. То есть обновляются координаты врагов и наносится урон башням.
А вьюха (тоже не один класс =)) просто обновляет визуальное представление соответственно текущему состоянию модели.

Контроллеры вижу тут примерно такие:
- Юзер, что-то кликнул (строим башню, выходим в меню, пауза и тд)
- Обновление всей модели на единицу времени

И еще,
Контролер содержит в себе модель и вью
Не совсем верно говорить "содержит", тк это подразумевает агрегацию,
а у тут более общий случай - композиция.

Psycho Tiger
02.01.2011, 23:20
Видимо я зря писал статьи про эмвэцэ. :(

terbooter
02.01.2011, 23:26
Psycho Tiger, нет не зря. Стиль подхвачен верно =)
"А хрен вам, овердамадж получили. Нету у нас больше хп"

Dukobpa3
02.01.2011, 23:56
Стиль не подхвачен, стиль в оригинале, так что попрошу;)

А почему у вас вьюха определяет что ее бъют?
Ок тогда вопрос. Кто это определяет?

Хотя вьюха жеж не понимает что ее бьют, она просто видит что враг близко, она ж тупая. Сиськи большие, а размер моска обратно пропорционален размеру сисек.

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

//**********************
Путаница опять:) Получается в таком случае лучше не плодить кучу контролеров на каждую башню и каждого врага, а попытаться обойтись одним контролером уровня. А там он уже будет глядеть: "враг1 на расстоянии выстрела башни1. Отдать башне1 команду стрелять". А башни и враги будут просто суб-вьюхами одной большой вьюхи уровня. Модели же башен и врагов будут просто суб-моделями модели уровня(ну типа в модели уровня где-то массив башен, и массив врагов.)

Psycho Tiger
03.01.2011, 00:01
Контроллер вертит моделями и определяет, были ли столкновения или нет. Заносит в модели инфу, если было столкновение.

Dukobpa3
03.01.2011, 00:20
Походу вкурил.

У меня были шоры на тему того что триада должна быть триадой.
Ну а теперь Вывод таков: надо не бояться делать к примеру один контроллер на пачку вьюх и пачку моделей.
И в то же время одна вьюха может быть целой триадой.

Как-то так. Вроде теперь всё ясно. Спасибо. (ну если я со своими выводами ошибся, то готов продолжить дискуссию)

Psycho Tiger
03.01.2011, 00:27
Ага, верно. Ровно как и вьюха может сосать 3-4 модели, так и один контроллер может отдавать приказы 3-4 вьюхам, так и контроллер может слушать 3-4 вьюхи, так и контроллер может менять 3-4 вьюхи.
И в то же время одна вьюха может быть целой триадой.
Триадой я бы её не назвал. Просто "компонент" для триады.

Dukobpa3
03.01.2011, 00:43
Просто "компонент" для триады.
Хз. Попытался возразить да передумал. Тут чтоб дальше продолжать предметный разговор нужно уже конкретно архитектуру приложения рисовать. А это не один час работы.

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

Оценка расстояния это ведь логика, потому этому действию место в контроллере. Башне ведь проще прошерстить 9 клеток (3х3) и сделать свой маленький массив из, к примеру, 3-х мобов в области своей видимости, нежели контролеру уровня каждый кадр шерстить всё поле и делать перерасстановку сил из 10-и башен и 40-а врагов.
//********************

Короче суть ясна. А дальше уже под каждое конкретное приложение своя архитектура нужна.
//********************
А если так глобально, то мне импонирует данная система:)) Куда удобнее работать с 10-ю классами по 50 строк каждый чем с одним классом на 500 строк ;)

cr0w312
11.01.2011, 07:42
Привет всем, тему не осилил(прочитал все, но в башке - каша), поэтому спрашиваю, контроллер(предположим игры) создает контроллер игрока, уровня и врага. Контроллер игрока в свою очередь создает модель игрока и вьюшку игрока, с уровнем и врагом - также, дальше что? модели ни про свои ни про чужие вьюшки не знают, расчет движения игрока/врага происходит в контроллере игры? Как устроить проверку столкновений? Или я путаю теплое с мягким?
ЗЫ. Код приводить не надо, тезисно.