Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   Статьи (http://www.flasher.ru/forum/forumdisplay.php?f=101)
-   -   Хорошее MVC (http://www.flasher.ru/forum/showthread.php?t=138349)

crazyone 31.10.2011 13:32

Раз уж пошла такая пьянка, расскажите мне пожалуйста, как организовывается многокнопочный интерфейс.
Ну, вот если есть панель управления, на которой 100500 кнопок типа загрузить картинку, загрузить документ, загрузить музыку, загрузить видео и т.д. Кто слушает все эти кнопочки и решает что дальше делать?

В голову просится ответ, что вьюшка слушает детей на предмет MouseEvent.CLICK, а потом диспатчит кастомное событие InterfaceEvent.LOAD_FILE с соответствующими свойствами.
Точно так же - если мы захотим повесить хоткеи на эти кнопки, то вьюшка будет слушать KeyboardEvent.KEY_DOWN и вещать те же самые события.

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

Это что-то внутри нужно безжалостно давить, или холить и лелеять?

Котяра 31.10.2011 18:09

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

crazyone 31.10.2011 18:40

Вот оно как, оказывается. Спасибо за пояснения.

ЗЫ Я кстати понял, почему мне древовидное ветвление в MVC тяжело дается. Пытаюсь думать кодом. А если нарисовать диаграмку, сразу так легко и понятно все становится.

tofflife 12.12.2011 20:29

MVP/MMVC больше подуше.

Spicelib, parsley нам в помощь.

fish_r 23.12.2011 14:45

Цитата:

Сообщение от Zebestov (Сообщение 1053206)
В любом MVC ни при каком раскладе и ни на каком этапе выполнения приложения входной точкой не должен становиться view, для которого все же существует controller. У меня он тоже "тонкий", но входная точка на каждом этапе приложения — именно контроллер. Именно он всех инициирует, собирает докучи и запускает в нужном порядке. Если не поздно — подумай над реорганизацией.

Т.е. как концептуально это выглядит? Примерно так?

Код AS3:

 
import flash.display.MovieClip;
import org.flashdevelop.utils.FlashViewer;
 
 
///Host
class Main extends MovieClip
{
        public function Main()
        {
                new Controller( this );
        }
}
 
 
///Controller
import flash.events.EventDispatcher;
 
class Controller extends EventDispatcher
{
        public function Controller(scene:Main, target:IEventDispatcher = null)
        {
                var model:Model = new Model();
                var view:Viewer = new Viewer(model);
                scene.addChild( view );
 
        }
}
 
///Model
class Model extends EventDispatcher
{
        public const READY_DATA:String = "ready data";
        public function Model()
        {
                ...
        }
}
 
 
///View
import flash.display.Sprite;
 
class Viewer extends Sprite
{
        public function Viewer(model:Model)
        {
                model.addEventListener( Model.READY_DATA, init);
        }
 
        private function init():void
        {
                ///start
        }
}


А кто представляет объект снаружи? Контроллер? Ну в данном случае, если напр. мейн захочет обратиться
к вьюеру.

Можно какой то мин. примерчик? Или пруф.

Zebestov 23.12.2011 16:44

Цитата:

Сообщение от fish_r (Сообщение 1053280)
Т.е. как концептуально это выглядит? Примерно так?

Примерно так.

Цитата:

Сообщение от fish_r (Сообщение 1053280)
Ну в данном случае, если напр. мейн захочет обратиться к вьюеру.

Что он там забыл? Main создал контроллер и ушел на заслуженный отдых. Отец семейства теперь — твой главный контроллер. И он может всегда дотянуться до своей вьюхи. А потом приложение должно перейти в другую стадию. Тот же контроллер создаст новый контроллер, тот в свою очередь полностью возьмет на себя новый этап приложения, создаст новый view и будет с ним работать сам. По окончании просто приберет за собой и сообщит "папе", что все закончено. Главный контроллер будет с нетерпением ждать этого сообщения, чтобы решать, куда идем дальше.

В общих чертах.

Psycho Tiger 23.12.2011 17:09

По сути, Main - контейнер для вьюшек и инициализатор контроллера.

etc 24.12.2011 15:13

Controller в принципе не должен знать, что такое Main.
Константы имён событий надо объявлять в самих событиях.

fish_r 24.12.2011 23:49

Цитата:

Сообщение от etc (Сообщение 1053437)
Controller в принципе не должен знать, что такое Main.

Да, конечно. Это пример написанный наспех. Контроллер может воспринимать Main как просто DOC, но мне все равно не нравится - не должен объект сам себя куда-то добавлять.

Цитата:

Константы имён событий надо объявлять в самих событиях.
Имеется в виду так?

Код AS3:

  [Event( name="some event" type="com.somepack.SomeClass" )]

Мне удобнее традиционным способом - видно перечень констант в панели Outline.

Psycho Tiger 25.12.2011 01:53

Цитата:

Имеется в виду так?
Нет, имеется ввиду определение этих констант в наследнике Event.

etc 25.12.2011 13:57

Цитата:

Сообщение от fish_r (Сообщение 1053490)
Да, конечно. Это пример написанный наспех. Контроллер может воспринимать Main как просто DOC, но мне все равно не нравится - не должен объект сам себя куда-то добавлять.

Кто куда кого добавляет? DOC, да, это логичнее.

Цитата:

Сообщение от fish_r (Сообщение 1053490)
Имеется в виду так?

Код AS3:

  [Event( name="some event" type="com.somepack.SomeClass" )]

Мне удобнее традиционным способом - видно перечень констант в панели Outline.

И [Event()] тоже, как раз в аутлайне и появится (это в FB во всяком случае). Тигра выше написал, что имелось ввиду.

fish_r 26.12.2011 20:04

Цитата:

Сообщение от etc (Сообщение 1053516)
Кто куда кого добавляет?

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

Оба варианта мне не нравятся, потому, что контроллер должен иметь дело с сигналами объектов, а не с манипуляцией объектами.

Цитата:

Нет, имеется ввиду определение этих констант в наследнике Event.
Цитата:

И [Event()] тоже, как раз в аутлайне и появится (это в FB во всяком случае). Тигра выше написал, что имелось ввиду.
Создание объекта расширяющего Event, с определением перечня каст. набора событий -
в результате мы получаем возможность подписываться на события инициализируемые другим объектом, даже не находящимся в области видимости подписчика? Это имеется в виду?

etc 27.12.2011 01:11

Цитата:

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

Оба варианта мне не нравятся, потому, что контроллер должен иметь дело с сигналами объектов, а не с манипуляцией объектами.

По мне так контроллер на то и контроллер, чтобы манипулировать.



Цитата:

Сообщение от fish_r (Сообщение 1053746)
Создание объекта расширяющего Event, с определением перечня каст. набора событий -
в результате мы получаем возможность подписываться на события инициализируемые другим объектом, даже не находящимся в области видимости подписчика? Это имеется в виду?

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

fish_r 27.12.2011 01:47

Цитата:

Сообщение от etc (Сообщение 1053775)
Нет, имелась ввиду лишь первая часть про создание кастомного события

Ну, а в чём бонус то? В этом случае.

Котяра 27.12.2011 02:05

Так принято. Не надо подписчику иметь импорт диспетчера (если ты там определяешь константы)

etc 27.12.2011 09:49

Цитата:

Сообщение от fish_r (Сообщение 1053776)
Ну, а в чём бонус то? В этом случае.

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

fish_r 28.12.2011 21:39

@Котяра, @_etc. Почитал, подумал... вы совершенно правы. Спасибо.

etc 30.12.2011 17:25

Ах да, я забыл, ещё такие события не всегда отсылает единственный диспетчер.

fish_r 31.12.2011 11:04

Цитата:

Сообщение от etc (Сообщение 1054464)
Ах да, я забыл, ещё такие события не всегда отсылает единственный диспетчер.

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

etc 31.12.2011 11:54

Глобальный — зло. Через него кто хочет и как хочет шлёт, в итоге отледить, что и откуда, невозможно.

Котяра 31.12.2011 18:22

Но многие таки используют. См. Spring и EventBus.

HardCoder 15.01.2012 21:15

Здравствуйте. Если подобное уже здесь обсуждалось, приношу извинения, ибо после 10 страниц чтения топика - перестал понимать о чем идет речь.
И так вопрос. Контроллер обработал некую информацию. В соответствии с этой информацией нужно провести изменения в представлении. Но дело в том, что эти изменения модели не касаются. Что делать? Напрашиваются такие варианты:
1. В контроллере есть же ссылка на представление, значит мы можем вызвать метод этой вьюшки прямо из контроллера. Но речь идет об "Хорошее MVC", согласно которому контроллер не должен изменять представление.
2. Через модель диспатчить событие, и ловить його в представлении. С точки зрения MVC - это хорошо, но с точки зрения программирования - корове седло. Зачем лишний посредник (модель) в этом случае?
Как грамотнее поступить?

Dukobpa3 15.01.2012 21:19

То что контроллер обрабатывает информаию уже не совсем академический мвц. Логика должна быть в модели если так чтоб совсем правильно.
Но у меня тоже мозг в контроллере:)

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

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

HardCoder 15.01.2012 21:38

Конкретный пример: Игра, изометрический плиточный мир, разные юниты в этом мире... Это все в контейнере - вьюхе. Контролер получает известие от одного юнита, что этот юнит переместился на другую плитку. Значит надо передать вьюхе что нужно отсортировать экранные обьекты. В модели есть массив этих экранных обьектов. Но в ней нигде нет информации на каком уровне глубины в дисплей-листе эти обьекты расположены. Значит в модели нечего менять, так как ей до фонаря как эти обьекты расположены по глубинам, на ход игры это не влияет. Контроллеру тоже до фонаря - его интересуют лишь x, y и пр. свойства. Единственный кому не наплевать - это представление, так как оно беспокоется о том чтобы пользователь правильно воспринимал происходящее.

Добавлено через 3 минуты
Цитата:

Сообщение от Dukobpa3 (Сообщение 1057081)
То что контроллер обрабатывает информаию уже не совсем академический мвц. Логика должна быть в модели если так чтоб совсем правильно.

Но если модель будет и хранить данные и обрабатывать их - зачем тогда нужен вообще контролер? Просто чтобы быть ненужным посредником между моделью и вьюхой?

Dukobpa3 15.01.2012 21:42

Ну координаты объекта ведь поменялись, значит очевидно же что надо отсортировать.
Следовательно мы организовываем вьюху таким образом чтобы каждый раз, как меняются координаты объекта всё что нужно - сортировалось. И контроллер тут ни при чем, равно как и модель.

Zebestov 15.01.2012 21:47

Цитата:

Значит в модели нечего менять
В модели изменятся X и Y юнита. Кто даст команду на перемещение — контроллер или отображение — в данном случае несущественно. Я бы делал это из контроллера.
Цитата:

Контроллеру тоже до фонаря - его интересуют лишь x, y и пр. свойства
Контроллеру неинтересны эти свойства, если он не заведует логикой (которой хорошо бы быть в модели).
Цитата:

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

Dukobpa3 15.01.2012 21:47

Цитата:

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

заказчик - вью
официант - контроллер
модель - кухня и прилавок

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

HardCoder 15.01.2012 22:05

Представление:

Берет из модели массив юнитов. Размещает их в дисплейлист. Она не знает на какие координаты их размещает. Координаты уже заранее предписаны каждому юниту во время их создания в контроллере. Но! она знает на какие глубины их размещать. Не важно откуда знает. Знает и все. Это ее дело заниматься сортировкой (удобным отображением), потому что именно она вызывает addChild-ы а не кто-то другой из триады.

Контроллер:

Получает известие от вьюшки что пользователь выбрал юнита, кликнул на карту и надо этот юнит переместить на место, куда кликнул пользователь. Контроллер лезет в массив юнитов (в модели) вытаскивает оттуда нужного юнита и говорит ему: "двигайся туда". Юнит покорно, при каждом шаге высчитывая новые координаты, двигается. То что он перемещается знает только он сам и юзер, который видит на экране перемещение. Когда юнит пришел на место - он сообщает конролеру, что тот прибыл. Контроллер знает что раз тот прибыл - значит положение изменилось и надо пересортировать карту. Что делать?
Бежим к модели - та курит в сторонке - ей вообще по барабану. Она знает что юнит никуда не делся из ее массива. Переместился? ну и что? Координаты можно узнать от самого юнита.
Так кто же должен сообщить вьюхе, которая понятия не имеет что произошло - что юнитов надо отсортировать?

Добавлено через 3 минуты
PS: повешать слушатель во вьшке на юнита мы не можем. Это может сделать только контроллер. Потому что вьюшка передает контроллеру что был произведен клик, а тот уже определяет с помощью сотен строк что дальше с ним делать (перемещать, атаковать, умирать) и отдает ему команды. Представление заранее не может знать что конкретный юнит будет перемещен.

Dukobpa3 15.01.2012 22:11

всё плохо:)

Модель: содержит набор абстрактных данных таких как координаты, имена и прочее. Без всяких визуальных объектов.
Представление: Содержит визуальную интерпретацию абстракций заложенных в модели. Например в модели у нас некий Object{type:type, x:x, y:y} - а вьюха уже знает что такой тип выглядит так, и находится по таким координатам.
Контроллер: получает от вью событие клика. Вносит в модель новые координаты объекта. На этом всё.
Вью: слышит маяк от модели что ее поменяли. Смотрит что поменяли координаты такого-то объекта, а текущие координаты то отличаются. И вот вью покорно начинает двигать объект с точки на точку с анимашками и прочими свистелками.

HardCoder 15.01.2012 22:12

Конечно, спасибо за ответы. Я понял что мой алгоритм - изначально не MVC. :) Буду учиться.

Dukobpa3 15.01.2012 22:16

Цитата:

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

HardCoder 15.01.2012 22:37

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

Dukobpa3 15.01.2012 22:42

Ну переписывать это кардинальное решение)
Как сделать я тебе уже ответил, чуть выше. Если хочешь можешь в личку/скайп стучаться.

fish_r 15.01.2012 22:53

Цитата:

Сообщение от Dukobpa3 (Сообщение 1057101)
Контроллер: получает от вью событие клика. Вносит в модель новые координаты объекта. На этом всё.
Вью: слышит маяк от модели что ее поменяли. Смотрит что поменяли координаты такого-то объекта, а текущие координаты то отличаются. И вот вью покорно начинает двигать объект с точки на точку с анимашками и прочими свистелками.

Модель не должны интересовать координаты объекта, для неё объект - некая статистическая единица, с набором соотв. информации (кол-во жизни, патронов и пр.), ИМХО, конечно (на классика пока не тяну )).
Думаю, что контроллер должен трансформировать данные из вью-типа в данные модель-типа, что собсно
и является его прямой обязанностью.

Цитата:

И так вопрос. Контроллер обработал некую информацию. В соответствии с этой информацией нужно провести изменения в представлении. Но дело в том, что эти изменения модели не касаются. Что делать? Напрашиваются такие варианты:
Если говорить не о "хорошем" MVC, а о классической реализации, то контроллер интерпретирует данные
и при необходимости изменяет вьюер (не знаю конкретики, но звено "контроллер", почти всегда лишнее, если события порождают информацию касающуюся только вьюера).

Dukobpa3 15.01.2012 22:57

Цитата:

Модель не должны интересовать координаты объекта,
В данном случае координаты это часть модели карты, поэтому они в модели быть должны.

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

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

HardCoder 15.01.2012 23:16

Значит, я так понял, что: классы юнитов это всего лишь каркасы, которые не должны нести графического представления? Они должны лишь иметь ссылку на класс графического обьекта который они представляют (король, солдат, дом...). А вьюха должна создавать не новые юниты и добавлять их на сцену, которыми оперирует контроллер, а новые анимашки (король, солдат...). Ой-ой-ой сколько же работы предстоит!!!

Dukobpa3 15.01.2012 23:24

Нет.
Каждый юнит это тоже моделька МВЦ, маленькая.
У каждого юнита есть модель
Есть вью
И возможно есть отдельный контроллер, а может и нет. Скорее всего контроллером всех юнитов будет этот главный контроллер.

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

Но это одна из частных реализаций, может быть и иначе.

fish_r 16.01.2012 02:43

Цитата:

Сообщение от Dukobpa3 (Сообщение 1057123)
В данном случае координаты это часть модели карты, поэтому они в модели быть должны.

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

Не знал, что классические принципы MVC уже изменились.

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

Dukobpa3 16.01.2012 02:46

Комент ради комента.

Я не то же самое сказал?

fish_r 16.01.2012 20:34

Цитата:

Сообщение от Dukobpa3 (Сообщение 1057161)
Комент ради комента.

нет


Цитата:

Я не то же самое сказал?
нет

/всё - 6 знаков, хотя оно того не стоило/


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

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