// codeart.ru / Вопрос/Ответ / Мое понимание архитектурного шаблона MVC Форум

Мое понимание архитектурного шаблона MVC rss подписка

Автор: Evgeniy Sergeev

Тормоз продолжает изучение ООП и недавно опубликовал пост о том, что ему не до конца понятен шаблон MVC. В надежде ему немного помочь расскажу о своем понимании этого шаблона. Вполне возможно эта информация окажется полезной кому-то еще.

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

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

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

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

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

В отличии от модели код контролера редко используется повторно. Да ему этого и не нужно. Задача контролера — дать удобство в сопровождении кода, в частности улучшить маштабируемость проекта. Контролер занимается тем, что вызывает нужные модели, передает им данные и получает результаты обработки этих данных. Поэтому, как правило, контролер содержит мало кода, а модель много.

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

Другая важная задача контролера выбрать каким образом представить полученные из модели данные. Например, модель вернула массив комментариев. Его можно представить в html, xml, json и т.д. Если оформлять данные непосредственно в методах контролера, то теряется удобство сопровождения — код контролера распухает и становится неповоротливым. Поэтому, данные передаются во вьюшки, которые уже оформляют их в пригодном для пользователя виде.

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

Вот пожалуй и все, что я хотел сказать про MVC.

P.S. Создал новую тему для обсуждения Нужно ли получать высшее образование.

  1. Шаблон MVC. Мысли про “состояние” модели
  1. Спасибо за статью. Сейчас как раз занимаюсь изучением MVC.
    Евгений, как вы считаете, проверка входящих данных должна производится в контроллере или в моделе?

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

  3. А вот как я вижу MVC:

    1. Запрос поступает в приложение и помещается в объект Request
    2. Request передается в роутер, который на его основе ищет нужный маршрут, маршрут в свою очередь содержит конечный контроллер и экшен, которые то нам и нужны.
    3. Имя контроллера и экшена записывается обратно в Request
    4. В игру вступает Dispatcher. Он на основе Request производит диспетчеризацию (вызывает экшен из контроллера), получает результат рендеринга View, и кладет все это в объект Response.
    5. Приложение завершает работу, отправляя Response клиенту.

    Когда при диспетчеризации вызывается экшен, то в экшене происходит рендеринг View (хотя, не обязательно). Так же, для получения/сохранения данных, в этом же экшене предварительно вызывается модель. И в самом конце работы экшена, происходит рендеринг View.

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

  4. Я тоже сейчас делаю примерно по такому же принципу. Фильтрация данных идёт в контролере, а в модели проверяется только на то, что данные не пустые и находятся в допустимых значениях для записи в БД.

  5. Andy, по-моему всё тоже самое только другими словами :)

  6. 2 Предводителев Сергей: нифига не «то же самое», ты внимательней прочитай пост автора — что-то я не заметил там ни слова про Request, Response, Dispatcher, Routing. Он что-то про модели и контроллеры рассказал — далеко не всё.

  7. Andy, так и вопрос был в общем описании шаблона MVC, А не описать все детали и подробности. Вы же написали тоже самое, только добавили Request, Response, Dispatcher, Routing, которые в данном контексте не важны, имхо…

  8. Перечитал еще раз статью. Какие-то странные утверждения:

    > Модель должна получать необходимые данные из вне, а не содержать их в себе

    Да ладно? А если мы делаем выборку из БД, данные-то будут храниться как раз в модели (Record). Модель это и есть данные, а так же то, как работать с этими данными.

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

    Это вообще что? Я не понял. Как это — теряет возможнось повторно использоваться? Каким это одним способом ее можно использовать?

    По-моему, автор скудно сечет в теме. Переубедите меня.

  9. Спасибо, интересно.

    Andy, зачем переубеждать? Лучше напиши свою статью )

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

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

  11. Зато не лень выпендриваться своим знанием?

  12. Это теперь называется выпендриваться? Я просто рассказал то, что знаю.

  13. Так ты же не рассказал ЧТО ты знаешь. Ты сделал следующее:

    1. Высказал мнение, что Евгений не шарит.
    2. Высказал предположение, что кроме тебя тут никто не шарит.
    3. Ну да, а ещё тебе лень тратить время на «подобное».

  14. Прошу прощения, что-то меня проглючило. Читал не все комментарии, а только нижние. Извините.

  15. > Высказал предположение, что кроме тебя тут никто не шарит.
    Не тут, а в моей конторе.

  16. Andy,

    >> Модель должна получать необходимые данные из вне, а не содержать их в себе

    >Да ладно? А если мы делаем выборку из БД, данные-то будут храниться как раз в модели (Record). Модель это и есть данные, а так же то, как работать с этими данными.

    Никогда не думал, что MVC — это шаблон который может использоваться не только под веб? И даже в вебе источник данных — это не только база данных? Про SOA приложения ничего не слышал? Или ты думаешь, что одна конкретная реализация шаблона MVC — это единственно возможная реализация?

    Я согласен что фраза «получает необходимые данные из вне» — может показаться туманной, но для этого вокруг нее есть и другие фразы. Смысл в том, что модель должна управляться контроллером. Этого можно достичь, например, используя принцип инверсии зависимостей.

    Если какой-то метод модели содержит конкретный SQL запрос к конкретной таблице — это плохой метод, потому что из-за него появляется жесткая связь между таблицами в БД и методом в модели. И такой метод уже нельзя будет использовать в другом окружении (в БД с другими именами таблицы), он всегда будет ломиться к одной и той же таблице и такое поведение я называю «единственный способ использования». При этом метод можно вызывать многократно, но он всегда будет делать одно и то же!

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

    Эмм.. А что такое «схема работы приложения на mvc»?

    > Одно я знаю точно, многие разрабы, работающие на ZF, даже не знают как обрабатывается запрос в MVC приложении.

    MVC — это не тип приложения, а архитектурный шаблон проектирования. В нем нет конкретики, это, если хотите, принцип построения приложений. Некий трехслойный пирог, где задачи делятся на три группы: отображение данных, обработка данных и управление первыми двумя процессам.

  17. Andy,

    > А если мы делаем выборку из БД, данные-то будут храниться как раз в модели (Record)

    Чтобы исключить недопонимание хочу пояснить следующее. В моем понимании если класс создан для того чтобы хранить данные, то это не модель, а источник данных (Datasource) или структура. Например, класс String — во многих языках это объект. Но ведь нельзя сказать, что String — это модель? Если немного развить эту идею, то если класс Comment создан для хранения некоторой структуры данных, то это не модель, а некий базовый типа для хранения данных со специфичной структурой. А моделью будет класс,который принимает на вход объекты типа Comment и выполняет над ними какие-то действия.

    При этом я ни в коем случае не утверждаю, что «модель» и «класс» — это одно и то же! Модель — это абстрактное понятие, которое может иметь много разных реализаций.

  18. >> Никогда не думал, что MVC — это шаблон который может использоваться не только под веб? И даже в вебе источник данных — это не только база данных? Про SOA приложения ничего не слышал? Или ты думаешь, что одна конкретная реализация шаблона MVC — это единственно возможная реализация?

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

    Только причем тут твое утверждение «Модель должна получать необходимые данные из вне, а не содержать их в себе» и твой теперешний ответ? Я реально, не нахожу связи между ними.

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

    И, конечно, нужно помнить, что представляет из себя модель в классическом понимании этого смысла, применительно к реляционным БД, таким как Doctrine или ActiveRecord. Для них модель, это инкапсулированные данные и методы, которые работыют с этими данными. А сама модель представляет и себя одну запись таблицы в реляционной БД.

    Надеюсь, мы поймем друг-друга. Жду вопросов.

  19. >Только причем тут твое утверждение “Модель должна получать необходимые данные из вне, а не содержать их в себе” и твой теперешний ответ? Я реально, не нахожу связи между ними.

    Попробую пояснить по-другому. Допустим у нас модель — это класс. Мы берем и создаем объект этого класса. Непосредственно в момент создания объект не содержит данных. Затем запускается конструктор который наполняет объект данными. И здесь по сути всего несколько вариантов — во-первых, присвоить значения переменной напрямую вбив его в конструкторе, во-вторых загрузить данные из какого-то источника (файл, бд, http) и в третьих получить данные из параметров конструктора. Конечно, можно сделать и позднюю загрузку данных через методы объекта. Но суть не в этом.

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

    Почему на мой взгляд это лучше? Потому что, например, прямая загрузка из бд уже не позволит использовать данные полученные по http в xml формате. А это ограничивает повторное использование модуля.

  20. >применительно к реляционным БД, таким как Doctrine или ActiveRecord.
    Че за каша у тебя в голове? Доктрина — это orm, а ActiveRecord — это шаблон проектирования который применяется в различных orm. Ни то ни другое бд не являются.

  21. >И, конечно, нужно помнить, что представляет из себя модель в классическом понимании этого смысла

    Еще один бред. Читай что такое MVC.

  22. > применительно к реляционным БД, таким как Doctrine или ActiveRecord.
    Криво построено предложение. Имеется в виду ORM, и то, и другое.

  23. Andy, даже если предположить что криво построено одно предложение, в остальном комментарии больше смысла не становится.

  24. Перечитал ещё раз внимательно и комментарии тоже. Ох и намутили воду ) Но, как ни парадоксально — что-то проясняется.

    У меня пока больше всего вопросов по вьюшкам. Что это, как оно работает? Это шаблонизатор выходит? Как его проектировать оптимально?

  25. Как я понимаю view — это как раз и есть шаблоны, в которые передаются данные для вывода. И весь html код должен быть именно во view.

  26. Схема работы… я имею в виду это: http://nethands.de/download/zenddispatch_en.pdf

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

  27. @Andy: с каких пор шаблон проектирования(MVC) сравнивают с конкретной реализацией (request, responce и пр.)?

    >А сама модель представляет и себя одну запись таблицы в реляционной БД.

    Это вообще заставило улыбнуться… Модель — это не данные (и уж точно не одна запись), а метод работы с данными. Точно так же модель может представлять из себя отдельную либу, написанную на c++ и работающую только с сетью — от этого она перестанет быть моделью?

    Такое ощущение, что Andy нахватался «умных» постов в форумах и принял их за аксиому. Вопрос для проверки — если убрать Request и Responce приложение перестанет быть построено на основе MVC? А если каждый запрос идет на свой файл, а не на index? =)

  28. > Вопрос для проверки — если убрать Request и Responce приложение перестанет быть построено на основе MVC?

    Нет, не перестанет. Дело в том, что я примерно описал процесс работы приложения для Тормоза.

    > А если каждый запрос идет на свой файл, а не на index?
    Тоже не перестанет. Просто если будет сделано именно так, то в этом случае маршрутизация будет вне приложения — откажешься от многих удобств, как например автоматическая генерация хелперов для указания ссылок в шаблонах.

    > Модель — это не данные (и уж точно не одна запись), а метод работы с данными.

    Ладно, согласен что модель это не данные, а методы управления данными. В роли модели во всех комментариях и имел в виду конкретную реализацию — паттерн ActiveRecord, имхо, наиболее популярный сейчас.
    Но вот, допустим, вы сделали следующее (active record):

    post = Post.find(777) # Нашли пост
    post # Теперь тут содержатся данные из БД

    Модель Post — одна запись таблицы. Объект post — так же одна запись таблицы.

    Получается, что в объекте post теперь инкапсулированы данные из таблицы. Разве нельзя сказать, что модель — это и данные и управление этими данными. Вот этот момент я упустил, кто расскажет об этом?

  29. Andy,
    > Разве нельзя сказать, что модель — это и данные и управление этими данными. Вот этот момент я упустил, кто расскажет об этом?

    А тут не может быть единого мнения. MVC — это общая идея. И разные программисты могут трактовать ее по-разному.

  30. >Модель Post — одна запись таблицы. Объект post — так же одна запись таблицы.

    Нет. Модель Post — это именно модель данных. А объект post — одна сущность базы (никак не таблицы!).

    >Получается, что в объекте post теперь инкапсулированы данные из таблицы. Разве нельзя сказать, что модель — это и данные и управление этими данными. Вот этот момент я упустил, кто расскажет об этом?

    Нет, нельзя. Объект — это не модель, и наоборот. Работая с объектом — работаете с данными (чаще всего). Работая с моделью — работаете с методами над данными.

    >Просто если будет сделано именно так, то в этом случае маршрутизация будет вне приложения — откажешься от многих удобств, как например автоматическая генерация хелперов для указания ссылок в шаблонах.

    Зависит от реализации. Кто мешает использовать кучу разных хелперов или даже один с магическими методами?

Leave a Reply

« »