![]() |
Опять MVC - как лучше?
Всем привет!
Очень хочу уточнить по поводу проектирования вопрос. Сомневался, куда запихнуть тему - быть может в флейм? Есть у меня некое приложение, построенное, на архитектуре MVC - то есть есть модель, в которой хранятся все данные, по сеттерам происходит некая логика и диспатч об изменениях, которые ловят интересующиеся вьюверы и отображают. Теперь к конкретике. Допустим, есть у меня машинка. То есть кузов, колеса, все дела. Соответственно - это класс, например, Car. И есть в модели некий параметр усилия, допустим, power, который обозначает кутящий момент двигателя. По нажатии, предположим, пробела, растет power, и когда он преодолевает момент сопротивления (вес машины и т.п.), машина должна начинать движение. Отсюда вопрос. Как лучше сделать? С одной стороны, с точки зрения ООП, логично, что есть объект машина - со своими свойствами, описанием, функциями. И может быть один-единственный параметр - скорость (которая может быть равна как нулю, так и отрицательным значениям), которую Car считывает из модели и, в связи с этим, уже внутри неё самой происходит куча всякой движухи - крутятся колеса, анимация дыма выхлопной трубы, быть может, даже звуки мотора и т.п. С другой стороны, если скрупулезно придерживаться mvc - обсчитываться должно все в модели - то есть rotation колес, например, положение головки воспроизведения, а viewer должно лишь только отображать и ничего более. Интересно ваше мнение - как вы считаете делать более правильно? Действительно ли вся логика должна быть в моделях, или, все-таки, приватная логика объектов должна находиться внутри них? ps: лично мне на данный момент импонирует второй вариант - когда в модели лежат некие главные параметры, а в объектах-вьюверах происходит всякая логика. Мне кажется, это больше отвечает принципу модульности. Или, может быть, такой подход уже есть и называется уже не MVC, а Model-View-Object, например? Или, может, я что-то упускаю? |
Забавно. Хотел создать отдельную тему для своих вопросов именно по MVC. Открыл форум, а тему уже ZergMaster создал. :) Поэтому с позволения воспользуюсь и докину ещё своих вопросов для профи.
Нормально ли это, когда вью не просто ждёт событий от модели, а сама ломится в модель, хватает её за какой-нибудь геттер и выдёргивает нужное значение? Поясню на примере. У меня в конструкторе дочернего компонента HeroView сразу выводится имя персонажа, причём это происходит именно в момент создания компонента и больше не меняется на всём протяжении его жизни. Спасибо. |
Цитата:
|
Модель должна интересоваться только теми данными, которые:
1) сохраняются между запусками приложения (на сервере или на клиенте) 2) непосредственно влияют на другие данные Другой способ описания гласит: модель хранит ТО, ЧТО отображается, а не ТО, КАК отображается. Но это описание спорное и скорее концептуальное, чем конкретное. Поскольку эти данные "КАК" очень часто приходится и сохранять в сейвах и использовать в рассчетах (координаты объектов например). Добавлено через 54 минуты То, как крутятся колеса, влияет на Результат? Нет? Это Вью. |
Цитата:
Цитата:
Цитата:
|
Цитата:
|
Цитата:
|
Друзья, подскажите ещё по MVC, плиз. Не получается по полочкам разложить. Аккурат к вопросу недавно упомянутого "ЧТО" и "КАК" :)
Кейс 1: У персонажа в игре есть есть статусы, т.е. свойства типа Boolean, которые меняют своё значение по ходу игры и оказывают влияние на другие параметры. Типичный пример: состояния персонажа из тактических игр или RPG: кровотечение, отравление, действие заклинаний и т.п. Это, безусловно, данные Модели. При этом некоторые (но не все) статусы должны явно выводится для пользователя в виде иконок. Это прерогатива CharacterView. Проблема следующая. Далеко не все подобные свойства нужно отображать пользователю. Кто должен "знать", какие из них подлежат выводу, а какие носят служебный характер? Мне кажется, что view, но я сомневаюсь. Кейс 2: по условиям игровой логики, накопление некоего свойства сверх установленного порогового значения открывает новые возможности. Типичная для многих жанров ситуация, когда, например, для проведения каких-то специальных атак требуется энергия или мана выше определённого заранее известного уровня. В модели всё понятно: есть значение порога (одного или нескольких), есть условие на превышение данного порога. При этом я хочу, чтобы во View персонажа выводились статус-иконки типа "готов к усиленным атакам" и "готов к супер-атакам". Как правильнее сделать с т.з. MVC? Мне видится либо вариант реализации в Модели этих статусов, т.е. создаём свойство для Character типа Boolean, чтобы при достижении порогового значения оно менялось с false на true и обратно, а view тогда просто отображает эти статусы, не приходя в сознание. Второй вариант - оставлять Модель как есть, ведь для её функционала ничего добавлять не нужно, а во view дописывать логику, что если такое-то значение свойства превысило такой-то порог (всё есть в Модели), это означает, что нужно пользователю вывести вот такую-то иконку. И ещё вопрос по технике. У нас главный View создаёт два CharacterView для игрока и противника. А в них - ещё пачка дочерних компонентов: изменяемые портреты, полоски здоровья, статус-иконки и т.п. Корректно ли будет со стороны CharacterView слушать напрямую модель своего персонажа, или всё-таки все данные от модели через главный View должны идти? И как родительские вью должны взаимодействовать с дочерними? У меня пока был только один уровень, с ним было всё просто: родительский компонент обращается к public методу дочернего и передаёт в него данные для отображения. А если таких уровней 3-4? |
1) Модель определяет, что МОЖНО показывать (через модификаторы доступа, то есть просто не дает доступа к тому что видеть не нужно). Вью решает, что из доступного НУЖНО показывать (в этом суть Вью и суть РАЗНЫХ Вью).
2) Если ни на что в Модели эти статусы не влияют, я бы повесил это на Вью. Вполне нормально для Вью иметь логику, сравнивающую какие-то данные из модели и производящую из этого новые данные, если они будут использованы только для отображения. Как пример — допустим в инвентаре ты водишь мышкой по разному оружию и внизу окна выводится сравнение с тем оружием, что у тебя сейчас в руках, типа "+15" или "-23", то есть сильнее или слабее. Ежу понятно, что эти +15 и -23 не хранятся ни в какой модели, на кой они нужны. Это все — повод для гордости данной Вьюхи, что она вот такое умеет, умница. И это на самом деле "КАК", а не "ЧТО", потому что "ЧТО" это просто убойка конкретного меча или пистолета, но ее можно показать "КАК" — в сравнении с убойкой другого оружия. В твоем случае есть "ЧТО" — уровень маны сейчас и другое "ЧТО" — необходимое количество маны. А "КАК" Вью это покажет — её дело. Может что-то замигает, что-то засветится, что-то перестанет светиться (в Скайриме например после использования Крика у персонажа должен "отдохнуть" Голос несколько секунд, и все это время светится индикатор, постепенно уменьшаясь). 3) В такой ситуации вполне допустимо для каждой вьюхи общаться напрямую со своей Моделью. Если Главной Вью тоже надо что-то знать о происходящем, она может тоже подписаться на нужную модель и получать те же данные, что и Вью персонажей. |
Огромное спасибо за комментарии. Пошёл дальше экспериментировать.
|
Камрады! Подскажите, пожалуйста, ещё по MVC для моего текстового квеста (кто не в теме, вот в этом сообщении буквально первые два предложения о механике).
Принципиальная схема работы такая: каждую итерацию модель рассчитывает и фиксирует изменение всех параметров, вью обновляет весь вывод. Дальше нужно взять имеющиеся действия (т.е. экземпляры класса Actions для возможных игровых действий, типа "ударить ножом в глаз" :)), по текущему сотоянию модели отобрать те из них, которые в данный момент доступны игроку, вывести их на экран и дождаться от него выбора. Это запускает следующую итерацию. Вопрос, кто конкретно должен "заведовать" этими самыми экземплярами действий? Кто должен создавать их и делать для игрока выборку доступных? Мне кажется, что Контроллер, но возможно я ошибаюсь. Просьба прокомментировать. Спасибо. |
вот ты сам пишешь
Цитата:
|
Так-то оно так, но меня всё-равно одолевают сомнения. Вот смотри, модель управляет логикой, делает расчёты и хранит в себе изменение всех существенных значений. Если посмотреть на описанную мной ситуацию, то в подборе доступных действий нет ни расчётов, ни изменения состояний. У контроллера есть ссылка на модель со всеми её потрохами, так что технически контроллер может выполнять такую функцию. Плюс в теории именно контроллер должен послать в модель сигнал о том, что ей пора работать. Что это будет, как не выбранное пользователем действие?
|
Насколько я понимаю, отсев действий происходит не в результате манипуляций пользователя (=контроллера), а в соответствии с параметрами модели. Поэтому и отвечает за это Модель. Ты делаешь ей запрос на доступные действия - она тебе их выдает. Никого не волнует, что происходит внутри модели. Вью интересует лишь результирующий массив действий, чтобы их отобразить, контроллер отвечает за то, чтобы сообщить модели о клике по выбранному действию. Всё.
|
Контроллер — самая тонкая часть MVC, он просто заведует течением работы приложения. Ждет отклика, пинает модель, ничего более. Создавать список доступных действий надо там, где игровая логика — в модели. Этот список должен быть доступен отображению, чтобы оно могло нарисовать все необходимое.
|
Кажется я понял, откуда такая любовь к контроллерам. Это место, в котором нет никакого страшного MVC: есть ссылка на модель "со всеми потрохами" и на Вью со всеми бубенцами, и можно писать код как в кадре, не заморачиваясь всякими ООП.
|
иногда мне кажется, что единственная задача контроллера - это не дать вьюхам напрямую дергать методы модели.Хотя тут высказывалось мнение,что контроллер еще должен заведовать всей клиент-серверной кухней.
|
Спасибо большое, господа, за содержательные ответы. Понял, согласился, отстал. Иронию, замеченную в некоторых репликах, считаю неуместной, т.к. нахожусь я в начале пути освоения ООП в целом и MVC в частности :) и без наивных вопросов никуда.
|
Wolsh
Цитата:
Добавлено через 4 минуты Я тут понял, что, любой объект - это модель. И мы можем произвести с этим объектом некоторые манипуляции, узнать некоторые его параметры, а также у него может быть некоторый view (но это не точно).. Это решает некоторые идеологические вопросы в моей голове, связанные с MVC.. ) |
Можно ещё вдогонку? Я сам не сомневался, но тут вас почитал и решил всё-таки уточнить. У меня выводится портрет персонажа в HUD. В зависимости от его состояния HP, подбирается нужный спрайт: от здоровенького, до залитого собственной кровищей (как в DOOM).
Пока вся логика выбора портрета целиком заложена во Вью. То есть при изменении параметров персонажа, вью "спрашивает" Модель, сколько HP осталось, и в зависимости от этого подбирает нужный портрет. И только Вью "знает", сколько всего спрайтов предусмотрено и для какого случая. Если я захочу, например, усложнить этот механизм, и к кровище на лице добавить выражения ярости или страха, в зависимости от значений других свойств, то всё равно вся эта логика останется во Вью. Верно? |
Цитата:
|
Логика "ЧТО" — уровень НР — в Модели,
логика "КАК" — какую картинку подобрать — во Вью. |
Друзья, подскажите ещё плиз на счёт MVC.
Имеем список действий, которые нужно предложить игроку. Их планируется объединить в группы - вполне традиционное решение для больших списков. Группа реализована через отдельный класс, содержащий строковый id для подбора лэйбла, глубину и массив элементов - id действий. Вопрос, где должны создаваться и храниться эти самые группы? Моя версия - Вью. Логика работы такая. Модель перебирает все возможные действия, отбирает среди них те, которые могут быть выполнены, и помещает их в массив. Этот массив передаётся Вью, которая "берёт в другую руку" известные заранее группы и выводит всё пользователю в нужном разрезе. При этом получается, если игрок выбирает опции, которые затрагивают лишь сам вывод (раскрыть группу или наоборот, вернуться назад), то все они отслеживаются и выполняются на уровне самой Вью. А выбор действия уже идёт в контроллер. |
Да, это правильно.
|
Друзья, у меня вопрос в продолжении предыдущего на счёт группировки возможных действий. Сделал, как и планировал: Модель отбирает все возможные варианты действий, передаёт массив во Вью. Вью "знает", какие действия в какие группы объединить, формирует список групп на экране. При клике пользователя группа "раскрывается", Вью выводит уже наименования действий для выбора. Выбор передаётся в контроллер. Работает.
Но для действий ещё нужен статус активности или неактивности. Для ситуаций, когда действие по проверке условий "проходит" и должно выводится пользователю, но в данный момент оно не может быть выполнено (т.к. например, находится на cooldown-e или какого-нибудь восполняемого параметра не хватает у персонажа). Для таких случаев я завёл ещё одну группу условий - условия активности. Сейчас запрограммировал следующим образом. При клике пользователя на группе, перед тем как она "раскроется", Вью перебирает все содержащиеся в ней действия (предварительно отобранные Моделью) и проверяет для каждого условия активности. Если условия выполнены - то выводится активная кнопка. Если - нет, но неактивная. Вопрос, правильно ли это с т.з. MVC? Смущает тот факт, что Вью фактически занято игровой логикой, хотя в данном случае последняя напрямую оказывает влияние на то, как отображать и как взаимодействовать с пользователем. Просьба прокомментировать. Спасибо. |
Я бы выдавал моделью только те действия, которые актуальны. Хотя если нужно, чтобы неактивные тоже отображались, то в каждом действии бы завел свойство .active и отображал по нему.
|
Согласен с ZergMaster, Вью не должна определять доступность действий. Это не та ситуация, когда кнопки временно "дизаблятся" вьюхой по соображениям UI или пока отыграет какая-то анимация. Здесь всё-таки доступность является вопросом игровой логики и основывается на данных модели.
|
ZergMaster, Wolsh, спасибо за ответ. Подтвердили мои сомнения :)
Цитата:
|
Цитата:
Флеш работает в одном потоке, и если делать какие-то тяжелые расчеты в момент нажития кнопки или раскрытия какого-то меню, это легко может привести к неприятным фризам. Лучше всего сразу скармливать вьюшке готовую информацию, чтобы она ее только отобразила. Очень сомневаюсь конечно, что в подобной игре есть какие-то ресурсоемкие вычисления Ну и второй момент. Он не касается конкретной игры, а скорее об играх в общем. Представим такую ситуацию: модель работает на сервере, а клиент представляет из себя только вью. Модель отдает вьюшке все необходимые данные, а она там у себя уже решает что отобразить, а что сделать не активным. Но с позиции модели активно все. Какой-то кулхацкер взламывает эту вьюшку и слегка правит код, чтобы ничего не блокировалось. Вуаля, ему доступны все действия и модель с удовольствием принимает все его решения. Я хочу сказать, что в подобном случае, это дикая дыра в безопасности. Ей непременно воспользуются, если игра станет хоть чуточку популярна |
caseyryan, спасибо, приму к сведению.
Цитата:
Да, тяжёлых расчётов пока не предвидится, это уже наверное такой перфекционизм новичка :) |
Задумался о таком вопросе. Тот самый исходный список отобранных действий (в виде вектора, заполненного соответствующими экземплярами) Вью запрашивает у модели, запуская её паблик-метод pickActions(). Данный метод - это не просто геттер, но полноценный алгоритм, осуществляющий перебор всех "заготовок", подстановку в них активных персонажей и отбирающий все, прошедшие проверку по условиям, чтобы выдать их на выходе. Вопрос, считается ли выполнение такой операции нарушением принципа MVC (Вью меняет Модель) или нет? Спасибо.
|
Всмысле, "вью запрашивает"? То есть, Вью о чем-то думает и потом такая "а что там у нас с доступными действиями?" :)
Вью не может о таком размышлять, Вью только реагирует на действия пользователя и события от Модели. Ну и да, методы она не запускает, ибо ничего не должна о них знать; только через Контроллер. Кто запускает цепочку событий, приводящую к необходимости Вью получить этот список? |
Ведь Вью может обращаться к Модели за данными? Может. Вполне нормальная ситуация, когда Модель говорит: "Список доступных для игрока действий в студию!", а Вью по этому событию и запрашивает. Вот я и сделал сначала просто геттер, а потом он как-то постепенно перерос в серьёзный такой метод. Как принято говорить в подобных случаях, так получилось. :rolleyes:
Ответ по существу понял, как переделывать тоже уже понятно. Делаю переменную в модели, все результаты складываю в неё, а Вью оставляю возможность просто получить её содержимое. |
Ещё мелкий вопрос по MVC возник. У меня в текстовом квесте формат выводимого пользователю текста (цвет, в первую очередь) может отличаться в зависимости от того, о ком идёт речь: герой, противник, повествование и т.п. ID каждой фразы генерирует Модель в зависимости от контекста, она же "знает", о ком идёт речь. Сейчас я сделал строковые ID форматов, которые хранятся в константах Модели и передаются вместе с ID фраз во Вью. Сами форматы - экземпляры TextFormat живут в форме публичных констант в отдельном классе пакета gui. Вью, получив массив инструкций от Модели, смотрит ID-шники формата в каждой инструкции, по нему подбирает нужный экземпляр TextFormat и засылает в область вывода - своему дочернему компоненту.
Вопрос. Не перемудрил ли я опять с системой задания форматов через строковые идентификаторы? Я исходил из принципа независимости Модели от конкретных способов вывода. Что типа сегодня это будут TextFormat-ы, а завтра - голограммы. Поэтому в Модели будут использоваться строковые ID, а как их обрабатывать - пусть Вью решает. Ведь можно дать Модели ссылку на TextFormat-ы и напрямую их выбирать и отправлять во Вью... |
Звучит хорошо. Если только эти строковые идентификаторы достаточно абстрактны, а не являются обязательными к исполнению жесткими указателями именно на текстформаты. Ну, в смысле, хорошо если это просто указатель на то, кому принадлежит данный текст (то есть, КТО?) а не на то, каким цветом его красить (т.е. КАК?). Хотелось бы, чтобы собственно формат и прочее оформление выбирала Вью (или голос синтезатора речи, или открывающую рот 3D-голову))))
|
Цитата:
|
По поводу оформления текста можно еще копнуть не в текстформат, а в CSS. То есть тексты сразу разметить как HTML, а форматирование хранить в классах CSS.
|
Модель содержит в себе всю деловую (предметную, buisness, domestic) логику и данные для оперирования с ее помощью. Модель сообщает её слушателям обо всех изменениях, произошедших в ней. Модель — это мозг приложения. Она очень развита и сложна. Сложнее неё ничего нет. Она есть основание, фундамент твоего приложения.
Ниже приведен пример неправильной трактовки модели. По мере возможностей избегайте такого. Это неправильная модель в MVC. Цитата:
В данное время я пишу серверное приложение на си шарп под юнити для моего любимого танк-шутера GWT, проекта, в котором я сейчас имею честь участвовать. Это приложение проверяет выстрелы, которые производят танки клиентов. Просто вычисляет место попадания каждого снаряда. Со всеми правилами (три калибра, десять калибров и пр.). Приложение может отрабатывать несколько боев для одной карты одновременно. Так вот... Я потратил около двух рабочих дней на портирование моих наработок со флеша: мой любимый самописный EventDispatcher и ещё некоторое количество абстрактных классов модели. Да-да, composite рулит везде. Кстати, еще полдня ушло на то, чтобы понять, что "их" GC безжалостен к enum и delegate. Но это выяснилось уже на стресс-тестах с профайлером. В итоге, за четыре дня я написал модель, которая контролирует бои и все объекты в этих боях. Оставалось дело за вьюхами (collider у unity) и контроллерами. Но это другая счастливая история. Вот так, малята. Если начинаешь MVC, то не забудь, что MVC начало тебя. Но это того стоит. Скорость разработки просто зашкаливает. |
Вложений: 1
Цитата:
Вложение 33205 |
Спс. Я не участвую в этом проекте чуть меньше двух лет. И того флэшера, который его поддерживал, уволили практически в то же время.
|
| Часовой пояс GMT +4, время: 14:53. |
Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.