Шаблон проектирования Singleton
Апр 20, 2010 PHP, Программирование
Добрый вечер!
Сегодня хотелось бы “пролить свет” на такую особенность создания крупных приложений, как Web направленности, так и оффлайн программ – как проектирование. Под проектированием системы понимается создание проекта программного обеспечения, на выходе мы должны иметь технический проект. Грамотное проектирование позволяет избежать многих проблем в будущем, связанных с расширением программы и доработками.
При проектировании программного обеспечения используют паттерны. Паттерн – это шаблон, т.е. готовое решение какой-либо задачи разработки ПО. При правильном подходе к проектированию и использованию шаблонов проектирования, мы получим мощный, гибкий, легко расширяемый и изменяемый программный код или продукт. Согласитесь это очень полезно, особенно тогда, когда проект разрастается до внушительных размеров.
Сегодня я попытаюсь рассказать о шаблоне проектирования Singleton.
Шаблон проектирования Singleton
Singleton – в переводе с английского – Одиночка. Основная цель данного шаблона проектирования – это возможность создания единственного объекта класса, именно это шаблон гарантирует. Данный шаблон проектирования, наверное, самый распространенный, так как может помогать решать достаточно большое количество задач в программировании.
Основными преимуществами использования данного шаблона, являются:
- контролируемый доступ к экземпляру класса;
- уменьшение числа глобальных переменных;
- возможность переменного числа экземпляров класса.
Реализация шаблона проектирования Singleton
Одиночка реализуется при помощи статической переменной класса, которую мы проверяем на существование, посмотрим на пример на языке программирования PHP 5:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?php class Singleton { // object instance private static $instance; private function __construct() {} private function __clone() {} public static function getInstance() { if (self::$instance === null) { self::$instance = new self; } return self::$instance; } public function doAction() { ... } } //Использование Singleton::getInstance()->doAction(); ?> |
В данном примере, мы имеем закрытую статическую переменную instance, которая, либо равна значению Null, либо содержит наш объект. Почему именно статическая переменная? Мы используем именно статическую переменную, так как она для всех порожденных объектов будет равна.
Принцип действия прост мы вызываем статический метод getInstance(), в котором проверяем существует или нет объект класса self, если существует, то возвращаем его и производим над ним какие-либо действия (метод doAction()), либо создаем новый объект.
Для примера, приведу реализацию на языке программирования C++:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | template<typename T> class Singleton { public: static T& Instance() { static T theSingleInstance; // у класса T есть конструктор по умолчанию return theSingleInstance; } }; class OnlyOne : public Singleton<OnlyOne> { //.. интерфейс класса }; |
В общем все тоже самое, только в синтаксисе языка C++.
Реальное применение шаблона проектирования Singleton
Реальное применение данного шаблона проектирования мы рассмотрим на примере задачи в области Web программирования, на языке PHP 5. При написании любых сайтов с применением PHP и баз данных, например MySQL, зачастую всегда необходимо следить за количеством подключений к той самой базе данных, чтобы сберечь ресурсы сервера. Именно для таких целей мы можем использовать данный шаблон.
Задача: позволить только одно подключение к базе данных. Реализация, как вы уже догадываетесь, на шаблоне проектирования Одиночка.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | class MySQLConnect { static $instances = 0; private $connection; private $select = ''; private $hostname = ''; private $username = ''; private $password = ''; // Конструктор класса public function __construct() { if(MySQLConnect::$instances == 0) { # Соединение $this -> connection = @mysql_connect($this -> hostname, $this -> username, $this -> password) or die(mysql_error()."Ошибка #: ".mysql_errno()); # Выбираем таблицу @mysql_select_db($this -> select); #Делаем так чтобы MySQL 4 и выше принимал русские буквы mysql_query("SET NAMES utf8_bin"); # Показываем что соединение установлено MySQLConnect::$instances = 1; }else{ $msg = "Соединение уже установленно!"; die($msg); } } // Закрыть соединение public function close() { MySQLConnect::$instances = 0; if(isset($this -> connection)) { @mysql_close($this -> connection); unset($this -> connection); } } } |
При использовании данного класса, мы сможем создать только один экземпляр класса MySQLConnect на странице, в случае попытки создать второй экземпляр, будет выведено сообщение “Соединение уже установленно!”.
Для того, чтобы и самому не следить сколько этих соединений уже создано на странице, достаточно переписать парочку строк:
1 2 3 4 5 6 7 8 9 | //if(MySQLConnect::$instances == 0) - меняем на: if(MySQLConnect::$instances === null) //$this -> connection = @mysql_connect($this -> hostname, $this -> username, $this -> password) or //die(mysql_error()."Ошибка #: ".mysql_errno()); - меняем на: MySQLConnect::$instances = @mysql_connect($this -> hostname, $this -> username, $this -> password) or //die(mysql_error()."Ошибка #: ".mysql_errno()); //$msg = "Соединение уже установленно!"; //die($msg); - меняем на: return MySQLConnect::$instances; |
Думаю принцип применения понятен. В WEB программировании случаи применения шаблона Singleton не ограничиваются только “слежкой” за соединением к базе данных. Надеюсь данная статья помогла разобраться с основами данного шаблона проектирования.
С уважением, Главный Лаборант.
_______________________________________________________________________________________
Интересный проект CMS для блога. Что уже сделано.
Советуем почитать:
Метки: PHP 5, Singleton, ООП, Паттерн, программирование, Проектирование, Шаблон проектирования




Островитянин, написал:
апреля 22, 2010 в 22:38
Здорово! Разъясни подробнее что имеешь в виду говоря:
. По моему весь смысл патерна в том что экземпляр у класса может быть только один. Пример не удачен по 2 причинам:
1. Синглитон подразумевает что доступ к конструктору из вне невозможен. У тебя же конструктор доступен из вне, как и статическое свойство $instances, следовательно путем присвоения свойству $instances NULL-значения, мы можем наштамповать любое количество экземпляра класса.
2. Оно менее кретично, но все же, если используешь ООП то используй его во всем. Ты же используешь функции работы с БД. Может стоит использовать объектно ориентированный интерфейс взаимодействия с БД, например mysqli, а синглитон пусть будет расширять класс работы с БД.
[Ответить на комментарий]
Главный Лаборант ответил на комментарий:
23 Апр 2010 в 6:13
Спасибо!
Да, обязательно просмотрю информацию по которой готовил пост и разбирался с данным шаблоном и отвечу на вопрос.
Насчет причин неудачного примера, да возможно…ну переменную закрыть – это легко, конструктор – тоже можно, но надо все перекроить – в общем соглашусь, что не совсем удачный пример
Если не трудно, то объясни второй пункт более подробно, просто не до конца понимаю, что именно не так.
Спасибо за комментарий
[Ответить на комментарий]
Островитянин ответил на комментарий:
23 Апр 2010 в 9:43
Не трудно, правда долго, вечером постараюсь, если время будет. Что скажешь насчет гостевого поста?
[Ответить на комментарий]
Главный Лаборант ответил на комментарий:
23 Апр 2010 в 10:13
Заранее спасибо! Очень интересно выслушать конструктивную критику.
Гостевой пост? Конечно за!
Кстати насчет вот этих строк:
Цитата из книги (Э.Гамма, Р.Хелм, Р. Джонсон, Д.Влиссидес “Приемы объектно-ориентированного проектирования. Паттерны проектирования.”, страница 132):
Увы, примера изменения данного метода пока не нашел, но если найду, то обязательно выложу.
Островитянин, написал:
апреля 23, 2010 в 15:12
Тогда я оформлю Своё видение и по 1 и по 2 пункту, а также как я понял про переменно число экземпляров, в виде статьи и пришлю тебе, ориентировочно в понедельник.
[Ответить на комментарий]
Главный Лаборант ответил на комментарий:
23 Апр 2010 в 15:23
Большое спасибо! Будет очень интересно почитать, тем более сейчас я пока только разбираюсь, поэтому вдвойне интересно и опять таки стимул разбираться, пробовать, исправляться
Если от меня будут требоваться ссылки или еще что, всегда запросто!
[Ответить на комментарий]