MVC: best practicies, или как Вы делаете?

samuel

Новичок
MVC: best practicies, или как Вы делаете?

Приветствую!
Собственно, поразмышляв на досуге об особенностях реализации данной парадигмами различными CMF, я обратил внимание, что ИМХО, роль Шаблонного Метода, реализуемая Акшенами (Application Controllers) и Моделью, слегка неудобна, по причине своей разбросанности...

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

... что вы думаете по поводу такого подхода?
... как лично вы делаете?

Спасибо.
 

StUV

Rotaredom
samuel
выделяет саму "Стратегию" и "Шаблонный Метод" в отдельную иерархию классов и т.д. и весь control-flow осуществляется только посредством их, но никак частично в Контроллере(Акшене) и частично в Моделе
немного подробнее плиз...
особенно о наличии в мвц-подходе "control-flow" в Модели
?
 

samuel

Новичок
control-flow в Модели в случае Active Model, Модели - которая управляет Представлением, а не просто инкапсулирует в себе часть бизнесс-логики - хранение информации (классический случай).

control-flow в такой Модели, реализует Шаблонный Метод и стратегию для своего представления. И то же самое делает контроллер.

Я собственно про то, что всё поведение вынести в какое-то другое логическое звено, Модели оставить роль только Провайдера Данных (абстракция источника данных и т.д.), контроллеру - только поведение Стратегии ( на Фабрике) по инстанциированию конкретной Композитной Стратегии, которая бы и являлась основным Шаблонным Методом/контрол-флоу для конкретного Варианта Использования (т.е. Экшна ?)
 

StUV

Rotaredom
samuel
хм...

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

т.е.:

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

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

whirlwind

TDD infected, paranoid
>я рассматриваю модель - как статичное представление данных
>все что относится к бизнес-логике приложения - есть контроллер

Контроллер - это прокладка. А если прокладка не нужна, ваше приложение не способно работать?
 

whirlwind

TDD infected, paranoid
На вскидку - длительный процесс по крону

PHP:
<?php
/*
===============================================================================
 2006/05/05
 $Id: close_adverts.php 237 2006-07-07 09:15:06Z whirlwind $
===============================================================================
*/

define("CLOSE_ADVERTS_FLAG","close_adverts");
define("DONT_AUTH",true);
include_once("init.php");
include_once("reference/constant.class.php");
include_once("operation/close_payment_period.class.php");

if ( isset($_SERVER["GATEWAY_INTERFACE"]) ) exit(1);
if ( !needClosing() ) exit(0);
$r = closePeriod();
resetFlags();
exit( $r ? 0 : 2);

function getConstant($name){
	$c = new Constant;
	if ( !$c->selectBy("name",$name) ){
		printf("Constant not found: %s\n",$name);
		return null;
	}
	return $c;
}

function closePeriod(){
	$a = new Advert;
	if ( !$a->filterBy("f_active",true)
		|| !$a->selectObjects() )
	{
		printf("Couldn't enum adverts\n");
		return null;
	}
	$errors = 0;
	while ( $a->next() ){
		$cpp = new Close_Payment_Period;
		$cpp->make();
		$cpp->set("advert",$a);
		$cpp->set("holdmoney_period",$a->get("holdmoney_period"));
		if ( !$cpp->calculatePeriods() ){
			printf("Calculate periods [%s] failed\n",$a->get("name"));
			$errors ++;
		}else if ( !$cpp->set("amount",$cpp->calculateCloseAmount()) ){
			printf("Calculate amount [%s] failed\n",$a->get("name"));
			$errors ++;
		}else if ( !$cpp->save() ){
			printf("Couldn't save document [%s]\n",$a->get("name"));
			$errors ++;
		}else{
			printf("Advert [%s] period +[%s,%s] -[%s,%s] amount [%s] CLOSED\n",
				$a->get("name"),$cpp->get("beg_positive"),$cpp->get("end_positive"),
				$cpp->get("beg_negative"),$cpp->get("end_negative"),
				$cpp->get("amount"));
		}
	}
	return $errors == 0 ? true : false;
}

function needClosing(){
	if ( ($flag = getConstant(CLOSE_ADVERTS_FLAG)) === null ) return false;
	return $flag->get("value") ? true : false;
}

function resetFlags(){
	if ( ($flag = getConstant(CLOSE_ADVERTS_FLAG)) === null ) return false;
	$flag->set("value","");
	return $flag->save();
}

?>
 

StUV

Rotaredom
whirlwind
=)
можно словами без кода?
в каких случаях из мвц исключается контроллер как "ненужная прокладка" ?

-~{}~ 25.07.06 15:40:

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

whirlwind

TDD infected, paranoid
я не говорил что "из мвц исключается контроллер". я говорил, что если бизнес-логику пихать в контроллер, то модель становится бессмысленным промежуточным звеном между хранилищем данных и пользователем этих данных.

-~{}~ 25.07.06 15:43:

>по самой логике ситуации мы получаем схему "модель-вью"
>значит, контроллер оказывается размазанным и там и там

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

-~{}~ 25.07.06 15:44:

ПС. из этого так же следует, что баг может возникнуть в модели и править его нужно только в модели.
 

StUV

Rotaredom
whirlwind
м.б. я не очень точно выразился...
модель предоставляет интерфейс для получения данных в виде объектов, представляющих сущности предметной области приложения
но все операции по манипулированию данными содержатся в контроллере...
 

whirlwind

TDD infected, paranoid
> модель предоставляет интерфейс для получения данных в виде объектов

Это скорее DAO, а не модель. Модель автомобиля - это только кузов с колесами или средство передвижения? ;)
 

StUV

Rotaredom
whirlwind
модель - это половина контроллера
значит мы не прийдем к консенсусу никогда ;)

-~{}~ 25.07.06 15:50:

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

-~{}~ 25.07.06 15:56:

в общем мы так уйдем в религиозно-терминологические споры
я всего-лишь ответил тредстартеру на вопрос "какой схемы мвц вы придерживаетесь"

я сторонник классической схемы:
http://builder.com.com/5100-6387-1044951.html

The Model holds the data displayed by the View and managed by the Controller. The View is responsible for delivering output to the user, and the Controller reacts to user actions and updates the Model appropriately.
;)
 

whirlwind

TDD infected, paranoid
Не, что бы не было непоняток :) Я не говорю что размазывать контроллер на модель и вью это хорошо. Я говорю что контроллер строится на основе модели (если это можно сделать, то почему бы этим не воспользоваться). В моем контроллере базовый получает экземпляр устойчивого класса, и на основе состава его атрибутов формирует реквизиты формы. Однако это не модель. Два отдельных этапа toModel и toForm непосредственно взаимодействуют с моделью. Все остальное манипулирует реквизитами. Это базовый контроллер. Любое поведение модели, которое нам не подходит, переопределяется в конечном контроллере унаследованном от базового. В наследнике можно сделать из реквизита, который представляет ссылочный атрибут модели, реквизит типа список и заполнить его в виде удобном для восприятия пользователем. Вот такое и аналогичное поведение у меня постепенно выделяется в отдельную категорию - контейнер. Т.е. помимо реквизитов еще и все необходимые для работы контроллера механизмы - потому что экшены почти всегда используют одни и те же методы контроллера. Грубо говоря ActionPreset вызывает только валидацию, без трансляции в модель и фиксации изменений, а ActionDelete выполняет только инициализацию (позицирование на экземпляре устойчивого объекта) и его удаление. Опять же позицирование на уровне контроллера, а удаление реализовано на уровне модели. Экшены только разруливают когда что делать. Эти же самые экшены легко биндятся к реквизитам, -> инициировать экшн можно изменив определенный реквизит в представлении. Вот так организуется фидбек.
 

StUV

Rotaredom
whirlwind
так и есть
все разногласия относятся к сфере терминологии - что относится к модели, а что к контроллеру
=)))
 

samuel

Новичок
к сожелению отсутствовал и не мог принять участие в беседе.
что относится к модели, а что к контроллеру
мда, но сама терминология есть ничто не иное, как нотация и описание поведения данного паттерна.
Что, на взгляд общественности, стоит понимать под контроллером или моделью, в соответствии с "современными" способами проектирования, в случае создания каркаса фреймвёрка?
Лично я предпочитаю на конкретный Контроллер (их Композицию - например, как в wact ) повесить всё поведение, присущее конкретному UC, в моделе держать только бизнесс-правила валидации данных и интерфейс абстракции от источника данных (например, как Symphony или activerecords в Rubby on Rails), и в Представлении (также композитном) - интерфейс к конкретному шаблонизатору (template view/transform view)

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

Я собственно, скорее про то, может кто уже "переделал" стандартное представление о Смолтолковском MVC, с учётом новых требований и специфик современных приложений - ЦМС/ЦМФ...

недавно попалась книга "php|architects Guide to PHP Design Patterns

но там, просто рассматривались МВЦ на активной и пассивной модели.

Быть может, мода на МВЦ уже сменилась чем-то другим?
 

whirlwind

TDD infected, paranoid
>в случае создания каркаса фреймвёрка
У мну ФВ вырос исключительно из модели. МВЦ - дело пятое, но если кривая модель или она заставляет себя "сильно дорабатывать" на каком либо этапе сопровождения, то ее сразу можно выкинуть в помойку.

>моделе держать только бизнесс-правила валидации данных и интерфейс абстракции от источника данных

Ну, ИМХО, неправильно это. Нормальный рефакторинг все расставит по своим местам. Например, есть продукты, есть страны, есть map стоплист по странам (т.е. запрет на доставку продукта в какую либо страну). Вот куда вы денете метод getStopCountries($products)? Я еще пойму если возникнет сомнение в класс страны или продукта, но неужели в контроллер? А если вам понадобится сделать кучу контроллеров с этой функции будете дублировать и дублировать? Или вынесете в отдельный файл (класс?). И как вы его классифицируете (назовете)? Самое место такому функционалу непосредственно в классе стоплиста и нигде иначе. По этому модель и бизнес логика тесно связана. А иначе никакого отличия такой модели от драйвера БД нет!
 

samuel

Новичок
Автор оригинала: whirlwind
Вот куда вы денете метод getStopCountries($products)? Я еще пойму если возникнет сомнение в класс страны или продукта, но неужели в контроллер?
... я видимо не совсем понятно выразился, что имею ввиду под моделью...
в данном случае, getStopCountries() инкапсулирует в себе получение данных от источника, валидацию и проч., и естественно, я отнесу её к конкретному классу модели, точнее к класу, используемым моделью в терминах БЛ...

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

StUV

Rotaredom
whirlwind
есть map стоплист по странам
Самое место такому функционалу непосредственно в классе стоплиста и нигде иначе.
эт что - return $this - ? =)))

По этому модель и бизнес логика тесно связана.
хм...
не могу твердо сказать, что это есть заблуждение на 100%...
но...
что скажешь по поводу реализации 100 различных бизнес-логиг в рамках одной модели?
Надеюсь идея ясна?
и валидадоры будут разные
и шлюзы работающие с ДАО
и вариантность поведения сущностей может быть разной...
имхо, при твоем подходе, на 100 задач в рамках одной предметной области ты будешь проектировать 100 моделей ?
переубеди меня =)

samuel
может кто уже "переделал" стандартное представление о Смолтолковском MVC, с учётом новых требований и специфик современных приложений - ЦМС/ЦМФ...
каких таких "требований и специфик" ?
 

whirlwind

TDD infected, paranoid
эт что - return $this - ? =)))
Нет. Есть карта. В ней есть метод стандартный для ORM карты getRelated(Persistent $object_to). Так вот getStopCountries(Array $products) это частный случай этого метода заточенный именно под специфику стоплиста. Как и getRelated, она возвращает экземпляр класса Country в режиме итератора.

>что скажешь по поводу реализации 100 различных бизнес-
логиг в рамках одной модели?

Не понял. Давай пример пжалста :)
 

StUV

Rotaredom
whirlwind
нуу.....
есть предметная область
есть сущности предметной области...

допустим есть завод
есть сотрудники завода
есть административный ресурс
есть развлекательный портал
одни и те же люди выступают в различных ролях
соответственно обладают не только различными "поведениями", но и ДА-Объекты будут другие...

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

на сколько я понимаю, я отнесу эти шлюзы к контроллеру, а ты к модели

так ? ;)
 
Сверху