[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Синглтон, фабрика и т.п.
Zhandos
Здравствуйте!
Где-то несколько дней вот изучаю паттерны, вещь весьма занятная. :)
Особенно меня заинтересовал паттерн "синглтон". Сразу же в голову приходит работа с бд. Где все приложение использует одно соединение.
Вот сделал небольшой скрипт.
Описание: есть две базы, в одной хранятся страны, в другой города. У этих таблиц есть три поля, id, имя, имя по русски.
цель: сделать вывод стран и городов. Сразу скажу цель обобщенная.

Для работы с бд существует класс-одиночка DBConn:

class DBConn
{
static private $_instance = null;
private $_db;

private function __clone(){}

private function __construct()
{
echo "connect!<br/>";
$this->_db = new PDO("mysql:host=localhost; dbname=you_db_name", "UserName", "UserPassword"); //соединение
}

static function getInstance()
{
if (self::$_instance == null)
{
self::$_instance = new DBConn();
}
return self::$_instance;
}

function getDb()
{
return $this->_db;
}
}


здесь я думаю все понятно, если объекта нет - создается. Через функцию getDb получаю соединение с базой.

Далее есть классы стран и городов, IdCountry и IdCity соответственно:

class IdName
{

protected $id;
protected $name;
protected $ru_name;

function getName()
{
return $this->name;
}

function getRuName()
{
return $this->ru_name;
}
}


class IdCountry extends IdName
{

}


class IdCity extends IdName
{

}


они унаследует некоторые общие черты от родителя IdName, так как в будущем возможно будут классы не только городов, но например других наименований (со своими особенными свойствами, но имя и имя по русски одно для всех :) ).
Не удивляйтесь что классы стран и городов пустые, там будут свои методы, я не стал пока на этом закорачиваться.

Далее я сделал два класса для выборок или стран или городов - BrowseCountry и BrowseCity.
Оба наследуются от BrowseMain, так как есть общие свойства, а реализации у многих может быть разной.
Так же я решил попробовать и паттерн "фабрика". Не знаю к месту ли. :D Но попытка не пытка...

Рассмотрим например выборку стран. У класса есть свойство $_country - оно хранит массив выбранных из базы стран. Есть общее для всех классов "Browse*" свойство sql- оно хранит соединение с базой. Тут я думаю правильно я тут все сделал (. Меня грызут сомнения. а не будет ли например при каждой передаче соединения через getDb в sql плодится сколько угодно соединений. Прошу извинить за тавтологию
Ну а далее я думаю все понятно.

class BrowseFactory
{
static $OBJ;
static function create($n)
{
switch ($n)
{
case "BrowseCountry":
self::$OBJ = new BrowseCountry();
break;
case "BrowseCity":
self::$OBJ = new BrowseCity();
break;
}
return self::$OBJ;
}
}

class BrowseMain
{
protected $sql;
protected $stmt;
protected $show_str;
function getStr()
{
return $this->show_str;
}
}

class BrowseCountry extends BrowseMain
{
private $_country;

function __construct()
{
try
{
$this->sql = DBConn::getInstance()->getDb();
$this->stmt = $this->sql->query("SELECT * FROM country_list");
$this->_country = $this->stmt->fetchAll(PDO::FETCH_CLASS, "IdCountry");
} catch (PDOException $e)
{
echo $e->getMessage();
}
foreach ($this->_country as $p)
{
$this->show_str .= $p->getName() . "<hr/>";
}
}
}

class BrowseCity extends BrowseMain
{
private $_city;

function __construct()
{
try
{
$this->sql = DBConn::getInstance()->getDb();
$this->stmt = $this->sql->query("SELECT * FROM city_list");
$this->_city = $this->stmt->fetchAll(PDO::FETCH_CLASS, "IdCity");
} catch (PDOException $e)
{
echo $e->getMessage();
}
foreach ($this->_city as $c)
{
$this->show_str .= $c->getName() . "<hr/>";
}
}
}


Ну и сам запуск выборок и вывод:

$browse_country = BrowseFactory::create("BrowseCountry");
echo "<b>Country</b><br/>".$browse_country->getStr();
$browse_city = BrowseFactory::create("BrowseCity");
echo "<b>City</b><br/>".$browse_city->getStr();

Как вы думаете на правильном ли я пути? И что в данном примере не правильно на ваш взгляд.
Заранее спасибо что потратили время на просмотр моего г#$@о кода.



Спустя 3 часа, 29 минут, 52 секунды (11.04.2011 - 04:40) kirik написал(а):
Цитата (Zhandos @ 10.04.2011 - 18:10)
не будет ли например при каждой передаче соединения через getDb в sql плодится сколько угодно соединений

Да нет.. метод DBConn::getInstance создаст экземпляр себя (вызовет конструктор) только один раз, а следовательно откроется только одно соединение.
Я бы вам посоветовал использовать вместо названия классов внутри себя - магическую переменную константу __CLASS__. И ещё если вы не собираетесь делать оберки PDO в классе DBConn, то можно исключить этап getInstance->getDb, и возвращать _db сразу из метода getInstance.

Спустя 8 часов, 38 минут, 59 секунд (11.04.2011 - 13:19) Zhandos написал(а):
Я просто думал если сделать присваивание переменной
sql = DBConn::getInstance()->getDb(); 

переменная $_db скопируется в sql.

Вот я провел небольшой эксперимент:
class TestSingle
{
static private $_instance = null;
public $test_varr = 1; //for example

private function __construct()
{
echo "create singleton<br/>";
}
private function __clone(){}

static function getInstance()
{
if (self::$_instance == null)
{
self::$_instance = new TestSingle();
}
return self::$_instance;
}
}


$obj1 = TestSingle::getInstance();
$obj2 = TestSingle::getInstance();
TestSingle::getInstance()->test_varr = 100;
echo "obj1_varr: ".$obj1->test_varr." obj2_varr: ".$obj2->test_varr." singleton_varr: ".TestSingle::getInstance()->test_varr."<br/>";
$obj1->test_varr = 33;
echo "obj1_varr: ".$obj1->test_varr." obj2_varr: ".$obj2->test_varr." singleton_varr: ".TestSingle::getInstance()->test_varr."<br/>";


И получается если где-то меняю переменную test_varr она меняется везде. То есть $obj1 и $obj2 являются ссылками, а не полноценными объектами?
Хотелось что бы кто-нибудь объяснил суть. :blink:

Спустя 15 минут, 25 секунд (11.04.2011 - 13:35) Nikitian написал(а):
Так вы реализуете синглтон и хотите, чтобы он работал как отдельные объекты. На то синглтон и нужен, чтобы создав его в разных местах получить один и тот же объект, а не несколько разных.

Спустя 4 минуты, 26 секунд (11.04.2011 - 13:39) neadekvat написал(а):
Цитата (Zhandos @ 11.04.2011 - 14:19)
То есть $obj1 и $obj2 являются ссылками, а не полноценными объектами?

Формально - да, это всего лишь ссылки на объекты в памяти. Вопрос только в том, на какие объекты. На один и тот же или на разные.
В вашем случаи на один и тот же.

Спустя 25 минут, 46 секунд (11.04.2011 - 14:05) Oyeme написал(а):
Да ссылками как же ещё.
Для клонирования объекта используй
$obj2 = clone $obj1;

Хотя зачем ты так всё усложняешь.

Спустя 8 минут, 27 секунд (11.04.2011 - 14:13) Zhandos написал(а):
Все понятно. Просто я заблуждался что передавая через return экземпляр синглтона он будет копироваться в переменную.
Спасибо всем! Надеюсь я не показался совсем уж тупым rolleyes.gif . Я только учусь.
Хороший тут форум, останусь тут. Надеюсь я никого не напрягаю? laugh.gif

Спустя 22 минуты, 20 секунд (11.04.2011 - 14:36) neadekvat написал(а):
Цитата (Zhandos @ 11.04.2011 - 15:13)
Надеюсь я не показался совсем уж тупым

Да бросьте, ООП - не самая простая вещь.
Посидите тут, увидите, какие порой вопросики задают..

Спустя 7 часов, 17 минут, 50 секунд (11.04.2011 - 21:54) kirik написал(а):
Цитата (Zhandos @ 11.04.2011 - 07:13)
Просто я заблуждался что передавая через return экземпляр синглтона он будет копироваться в переменную.

Это было верно для PHP4.
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.