Почему Singelton - плохая практика?

  • Автор темы Духовность™
  • Дата начала

Активист

Активист
Команда форума
> Опять же - если этот объект будет "настраиваемым", то война всё равно будет....
А кто мешает настраивать одиночку, не пойму. Ну настрайвате его как хотите в процессе работы, творите с ним что угодно, хотите - вводите методы, меняйте свойства, пожалуйста, но если по архитектуре он только один, то это одиночка, а если нет - то не одиночка.

Одиночки по определению - класс парсера ЧПУ (URL не изменится на всем протяжении работы сайта), дебагер (одиночка, он пишет в один файл, указанный в его настройках) и т.п..
Не одиночка - товар в группе, группа, модуль, виджет и т.п., т.е., в ОЗУ этого приложения может будет > 1 объекта.

Представим, что в ОС у вас появилось два init.d, что они будут творить с вашими сервисами? Два syslogd - один пишет, второй ждет, открыть не может.

Одиночка - не значит константа, консерватор, это "лидер", как прездент РФ )) У него есть интерфес доступа - ВВП, он сцуко тоже одиночка, а вот у ВВП уже есть много разных министров)))
 

Активист

Активист
Команда форума
Отличие синглтона от обычного объекта - это статическое свойство - Я, и закрытый метод __clone, все, тот же самый объект с теме же самыми свойствами! При вызове синглтона вы будете уверены, что вы позвали именно его, а не кого-то другого.
 

HraKK

Мудак
Команда форума
Активист
Я признаю только 1 одиночку ядро, не из-за того что другие классы не могут быть одиночками, а потому что не хочется вводить прослойку, как у Григория, которая позволит подменять одиночку, на каждую одиночку. У меня прослойка только на ядро.
 

Активист

Активист
Команда форума
HraKK
У меня также - только ядро, есть дока где описано как им пользоваться, про другие классы я привел просто описание, что такое быть может, что бы был более понятен смысл одиночек.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Одиночка - не значит константа, консерватор, это "лидер", как прездент РФ )) У него есть интерфес доступа - ВВП, он сцуко тоже одиночка, а вот у ВВП уже есть много разных министров)))
Т.е. использование синглтона - вопрос устройства политической системы и религии.
Вы можете иметь одно ядро/президента, два, как в России, или ни одного, как в парламентских республиках.

Активист
не хочется вводить прослойку, как у Григория, которая позволит подменять одиночку, на каждую одиночку.
У ваших ядер главная функция - получение другого объекта.
Я убрал этап создания объекта ядра, получаю объект напрямую статически.
 

HraKK

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

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Core_Application - такая же прослойка.

Все эти задачи, для которых вы используете синглтоны: реестр объектов, лог, init.d, дебаггер - просто функции, которые не хранят состояние, т.е. статические методы.
Парсер ЧПУ хранит результат, но в рамках вызова этот результат предопределен, независим, неизменен, и по сути статическая константа.

Возможно, у твоего объекта есть некая функциональность объекта, но мне она неизвестна.
 

whirlwind

TDD infected, paranoid
блаблаблабла... Этот спор никогда не закончится, пока паттерн не будет рассматриваться со стороны пользовательского кода. А пользователю (класса) в большинстве случаев просто накласть кто он там сингельтон иле моветон, так же как каждому из вас все равно как зовут гаишника который вам ТО пропечатает, скока у него детей и женат ли он вообще. Одиночка - нефункциональное требование и рассматривать его с точки зрения функциональности смысла никакого нет.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Интересно, а с кем ты разговариваешь? :)
Я просто не понимаю взаимосвязи твоих фраз, извини.

whirlwind, я не спорю, а просто просил примеры использования - и объяснить почему так, а не иначе.
Это ведь интересно - узнать, как пишут и думают другие.
флоппик рассказал, спасибо
А другие, к сожалению, пишут лирические опусы из области администрирования, политики, верований и тайного знания.
 

AmdY

Пью пиво
Команда форума
Духовность™
респект, я здесь родил новый подход для своего фреймворка.
создал единую точку класс
PHP:
<?php

class Kiss_Service {

	protected static $run = false;
	protected $services = array();

	public function __construct() {
		if (self::$run) {
			throw new Exception('Locator: already running');
		}
	}

	public function addService($serviceValue, $serviceName = null) {
		$serviceName = $serviceName ? $serviceName : get_class($serviceName);
		if (!isset($this->services[$serviceName])) {
			$this->services[$serviceName] = $serviceValue;
		} else {
			throw new Exception("Locato: already have service: $serviceName");
		}
	}

	public function &__get($serviceName) {
		if (isset($this->services[$serviceName])) {
			return $this->services[$serviceName];
		}
	}

	/**
	 *
	 * @return Kiss_Request
	 */
	public function getRequest() {
		if (!isset($this->services['Request'])) {
			$this->addService(new Kiss_Request(), 'Request');
		}
		return $this->Request;
	}

	/**
	 * @return Kiss_Config
	 */
	public function getConfig() {
		if (!isset($this->services['Config'])) {
			$this->addService(new Kiss_Config(), 'Config');
		}
		return $this->Config;
	}

}
?>
принцип такой:
создал единую точку по аналогии с лимбовским тулкитом, но без вских mixin.
заткнул конструктор, чтобы сервис можно было инициализировать лишь единожды, но при этом не использовал singleton, чтобы им не могли воспользоваться в любой части приложения (списибо korchasa за идею контекста для реестра).
использовал для добавления сервисов используется метод позволяющий только добавлять новые, без возможности переназначить (спасибо fixxxer за пояснение идеи реестра).
создал предефайненные методы для основных сервисов, возможно addService вообще сделаю закрытым, чтобы сервисы не добавлялись извне.
в начале инициализирую сервис и передаю объект в конструкторы
в конструкторе берутся нужные сервисы и присваиваются атрибутам класс, для удобной работы с ними, сам сервис в классе за пределами конструктора не .

получился этакий приручённый god object.

жду критики.

p.s. За час написал класс и переделал фреймворк под него, в очередной раз убедился, что гибкость web фреймворкам нафик не нужна (ну почти).
p.p.s. Вылезли грабли с ленивой инициализацией шаблонизатора, поэтому в контроллере прародителе сделал пришлось сделать private атрибут для работы с сервисом.
 

флоппик

promotor fidei
Команда форума
Партнер клуба
Твой пример развалится на моменте, когда ты захочешь запихнуть 2 разных бд :) Или когда захочешь запихнуть код, написанный не тобой, и требующий передачи данных в конструктор, это конечно можно решить оберткой, но - если это какой нить мейлер с тремя десятками классов, заворачивать каждый, и делать это при новой версии — не очень удобно. Ты вводишь кучу соглашений на предмет названий этих сервисов, которые должны знать все классы, которые пользуются твоим локатором.

Мне было бы интересно узнать, как бы ты решил эти проблемы.
 

HraKK

Мудак
Команда форума
чот не впечатлило. Вообще никак. Проблем не решает, а лишь создает. Не прозрачный ну не разу.
 

AmdY

Пью пиво
Команда форума
флоппик
>>запихнуть 2 разных бд
а что мешает добавить два коннекшина?
PHP:
$service = new Kiss_Service();
$service->addService(new Kiss_Db('...'), 'DbSlave');

$service->getDb() // дефолтное соединение Db
$service->DbSlave // соединение DbSlave
>>
>>захочешь запихнуть код, написанный не тобой, и требующий передачи данных в конструктор
это никак не связано с сервисом, стороннему коду как и при любом другом подходе передаётся данные в конструктор, не нужно ничего даже оборачивать.
>>Ты вводишь кучу соглашений на предмет названий этих сервисов, которые должны знать все классы, которые пользуются твоим локатором.
соответственно, как и при других подходах, нужно знать имя. по идее все основные сервисы должны быть заранее вшиты и показываться на $service->get<Серсис>() покрытый phpdoc-ом и с работающим автокомплитом.
единственная договорённость - это принимать объект Kiss_Service, но так как эта договорённость используется только на уровне фреймворка для таскания данных, то пользователь не ощутит никаких изменений, контроллеры не требуют никаких изменений. Я же писал, что замена прошла мгновенно.

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

HraKK

Мудак
Команда форума
А я понял что ты сделал, да у меня тоже такое есть. Только чуть лучше - я добавил туда Lazy чтоб не таскать не нужное.
 

AmdY

Пью пиво
Команда форума
HraKK
у меня lazy не получится, я почему-то решил его не передавать выше ядра, чтобы не использовали как реестр. надо это осмыслить свежим взглядом, это решит проблему lazy и конструкторов. а после формирования в ядре можно заморозить addService. тогда можно lazy сделать на этом уровне, а не разбрасывать в реализациях.
 
Сверху