?

Log in

No account? Create an account
Main

Меня беспокоит Гондурас

Так беспокоит, что я положил пост в ру_пхп

Если не трудно, прокомментируйте:
Предлагаю обсудить плохие стороны паттерна Singleton

Comments

щас набегут
и хорошо. нужно предельно четко понимать, что хорошо, а что плохо.

потому, что лексикон типа "кто использует синглтон, вон из профессии" не несет в себе информации...
Фраза жесткая, конечно.

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

Если взять пример с lang из той темы. Если архитектура хорошо продумана, то наличие таких классов как Application вполне оправдано может быть, ведь мы же его придумали :) Другое дело, что такой класс, который имеет изменяемый параметр (как в случае с $objectRender), не должен зависеть от Application. Ведь есть же какая-то логика, которая должна определять когда какой lang использовать. И где она эта логика должна находиться? Поместить ее внутрь класса === завязать на конкретный фреймворк/архитектуру. А хотелось бы, чтобы эту логику можно было бы изменять, то есть она должна быть в каком-то другом месте, и эта логика должна решать, откуда вытащить lang, из Application или из другого места.
Так как бы 90% случаев, это в самом главном контроллере определили язык. И после этого он один для всех объектов. Что соблазняет на вот такой подход, что я написал.

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

Да завязались на Application, но в противном случае придется этот языковой параметр тащить по цепочке из объекта objectRender, в остроитель запросов, и в загрузку массива языковых переменных. Хотя в данном конкретном случае вроде и не так много получается таких протаскиваний.
Тогда наверное стоит этот render поменять? Я же не в курсе реализации. Просто полагаю, можно было бы логику во вне вытащить.
pubblic function someAction($data){
if($some_logic_here){
$lng=Application::getLang();
}else{
$lng=$data['lang'];
}
$content=$this->service('someservice')->getMessage($id,$lng);
$objectRender=new SomeObjectClass($tpl);
return $object->render($content);
}

Может что-то типа такого? Я предполагаю смысл действия по слову render() и могу ошибаться, конечно. В смысле странно, что в render()'у зачем-то нужен lang. И даже если нужен, то не для выдергивания из базы имхо.
угу, что-то типа этого и надо было сделать, да.

название видимо render не совсем удачно, т.к. по сути это экшен конечно.
У меня вообще логика примерно такая:
// ... из класса экшенов
public function showMessage($data){
 return $this->messages()->getMessage($data['id']);
}
// ... из класса render'ов
public function showMessage($content,$tpl){
 return $content;
}
// ...
public function execAction($name,$data){
 $content=call_user_func($this->actions[$name]['action'],$data);
 if(isset($this->action[$name]['view'])){
  $content=call_user_func($this->actions[$name]['view'],$content);
 }
 return $content;
}


В итоге все вызовы идут через обертку execAction, которая чуть сложнее чем тут, то есть настраивать ее можно, но смысл тот же. Реализовать этот метод каждый модуль может как хочет через наследование. Но как показала практика, ничего такого не надо, просто заполнять массивы типа $this->action.

И тогда сам класс выглядит примерно так:
class CMS_Module_Module_PrivateMessages extends CMS_ModulesManager_Module_Module{
	protected
		$tpls=array(
			'showCreateMessageForm'=>'message_form',
			'showPMMain'=>'main',
			'showNavigation'=>'navigation',
			'showUserTagsList'=>'tags_list',
			'showMessagesList'=>'messages_list',
			'showMessage'=>'view_message',
		);
	protected
		$actions=array(
			'showSentMessagesList'=>array(
				'view_function'=>'showMessagesList',
			),
		);
	protected
		$work_units=array(
			'WorkUnit.PrivateMessages_UI',
		),
		$views=array(
			'View.PrivateMessages_UI',
		);
}
у меня что-то похожее тоже есть...

надо будет описать как-нибудь такого рода организацию и тоже бы разобрать внимательно.
наверное и сам такой рендер не хорош, надо подумать будет.
Я его использую для lazy initialization. Тут глобальными переменными не обойтись. А инициализировать все сразу - очень дорого.
Может просто надо продумать механизм инициализации заранее?
$obj->events();

protected function events(){
 if(is_null($this->events)){
  $this->events=Events()->getEventsObject();
 }
 return $this->events;
}

Тоже lazy, только это не обязательно должен быть singleton, а фабрика, к примеру.
И кстати, подобные lazy вещи - это попытка перенести логику работы в класс и избавить себя от необходимости обрабатывать и хранить настройки. Надо попытаться спроектировать так, чтобы все можно было настроить, при этом постараться локализовать настраивающие механизмы в одном месте.
> подобные lazy вещи - это попытка перенести логику работы в класс и избавить себя от необходимости обрабатывать и хранить настройки

так и есть - сложность либо в конфигурации, либо в коде.
Или тупо в объемах данных, связанных с каждым объектом, да?

(Anonymous)

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

Ну, это описание чуть менее чем всех php-задач, якобы статические классы не надо инициализировать и потому они быстрее. Но во-первых http://sontar.livejournal.com/145721.html
во-вторых инициализировать можно те объекты, которые нам понадобятся при выполнении данного запроса
в-третьих, есть такие штуки как apc, eaccelerator итд
в четвёртых, ресурсы занимают не сами объекты, а хранимые в них данные
OMG. Хотел бы я так рассуждать про все задачи на свете. А я ведь даже не про PHP говорю.
для пущего эффекта надо сделать так:

ребята, не ссорьтесь :)))))

про не пхп, это я должен был вовремя предупредить, my fault...
Заранее сжирает много времени. И, вообще, открытие кучи файлов (гигабайтного размера) их map в память - недешевая процедура (пусть даже и файлы грузятся в память не целиком). Особенно, когда каждый запрос не требует открытия всех файлов. Поэтому так или иначе их лучше всего инициализировать лениво.
PS: Фабрика классов - это тот же singleton, вид сбоку.

Edited at 2010-05-25 03:47 pm (UTC)