Есть класс-родитель. Creators. В нем реализация синглтона и синглтона с поддержкой нескольких инстанций. Из класса-потомка нужно задавать настройку: у нас может быть одна инстанция класса или множество. Как это лучше сделать?
Лучше не использовать синглтон таким способом. Создай Builder или Factory и получай синглтон от них. Но с наследованием это никак не связано.
просто в фабрику нужно передавать имя класса и она его создает.. А я думаю это сделать через наследование а конструктор создаваемого класса - протектед.
Используй кодогенерацию внутри фабрики. Никто тебя не обязывал иметь уже готовый класс, ты можешь его генерировать по определенным правилам из определенного шаблона. Наследование от Синглтона - суть ошибка архитектуры. P.S. А что собственно надо? может тебя устроит, к примеру, Registry?
Мда, это я загнул насчет фабрики (пожалуй не стоит в ней использовать кодогенерацию). Но в Builder ты точно можешь использовать кодогенерацию.
ACL! PHP: <?php class PermissionsManager extends UsersCommon { private static $instance = NULL; private $users = array(); private $data = array( 'rules' => array(), 'groups' => array(), 'users' => array() ); private function __construct() { $this->db = Database::getInstance(); } public static function instance() { return (self::$instance) ? self::$instance : self::$instance = new self; } public function addRule($title) { // ... class UsersManager extends UsersCommon { private static $instance = NULL; private $fields = array(); private function __construct() { $this->db = Database::getInstance(); } public static function instance() { return (self::$instance) ? self::$instance : self::$instance = new self; } public static function generateSalt($length = 3) { // ... class UsersFields extends UsersCommon { private static $instance = NULL; private $fields = array(); private function __construct() { $this->db = Database::getInstance(); } public static function instance() { return (self::$instance) ? self::$instance : self::$instance = new self; } /** * UsersFields::add() * * @param string $title * @param int $type * @return int fieldId */ public function add($title, $type) { // ... class Users extends UsersCommon { private static $instance = NULL; private $permissions = array(); private $groups = array(); private $users = array(); //# private $resources = array(); private $userData = array( 'id' => array(), 'name' => array(), 'mail' => array() ); private function __construct() { $this->db = Database::getInstance(); } public static function instance() { return (self::$instance) ? self::$instance : self::$instance = new self; } // ... class User extends UsersCommon { private static $instance = NULL; private $users; private $userId = NULL; private $passHash = NULL; private $needReCheckAuth = true; private $isAuthenticated = false; private function __construct() { $this->db = Database::getInstance(); $this->users = Users::instance(); $this->userId = isset($_COOKIE[self::COOKIE_NAME_ID]) ? $_COOKIE[self::COOKIE_NAME_ID] : NULL; $this->passHash = isset($_COOKIE[self::COOKIE_NAME_HASH]) ? $_COOKIE[self::COOKIE_NAME_HASH] : NULL; } public static function instance() { return (self::$instance) ? self::$instance : self::$instance = new self; } + есть Rewrite - синглтон + Database - множество инстанций + FormValidator - множество инстанций + NewsCollection + ContentCollection + ... знаю, что наследовать от синглтона глупо, но тут выделение класса так и просится
Наследовать не только глупо, оно еще и работать без костылей не будет. Какие методы ты хочешь унаследовать от Синглтона? Только контроль количества инстансов?
Смысла нет. Весь Синглтон это 2 свойства и 1 метод из 3 строк. В общем, не ленись, а просто пропиши. Поверь опыту - это целесообразнее и проблем меньше В крайнем случае создай template в IDE для Синглтонов Максимум что можешь сделать это передавать иницализацию БД PHP: $user = User::getInstance(DB::getInstance()); Это позволит убрать статическую зависимость от прослойки БД. Если так уж хочется облегчить работу, то подумай над кодогенерацией. Хотя при тех объемах кода, что ты привел... Смысла тоже мало, но даст опыт
Синглтон - это в первую очередь идея, а не паттерн, инстанция должна быть одна. Что есть Creators? Parent?
Инстанций у Синглтона может и больше быть Фокус именно в контроле их числа. И, да, не стоит путать паттерн программирования и паттерн(шаблон) кода. Паттерн программирования - это методика решения задачи, а не конкретная ее реализация. Паттерн(шаблон) кода - это заготовка.
Creators - реализация создания нескольких экземпляров классов и получения их через метки. Его используют FormValidator, FV_Advanced, NewsCollection. PHP: <? NewsCollection::create('someNews') ->orderBy('date', 'ASK'); // ... if (isset($_GET['cid']) NewsCollection::getInstance('someNews') ->filterBy('category', $_GET['cid']) // ... NewsCollection::getInstance('someNews') ->get('links', 'title', 'short_text');
например я не знаю: создан ли уже экземпляр Rewrites. Я-то обращусь в регистр за ним, а если его там нет? Можно создавать и помещать его туда, но тогда уж проще оставить все как есть: + один метод и одно свойство
Кажется, понял проблему. Не вижу разницы принципиальной разницы, между одной или несколькими инстанциями - методу getInstance сделать параметр необязательным. Если он не передан, то считается, что одна (первая).
[vs] даа! Это оно. Именно по такому принципу и сделан класс Creators. Но получается что мы извне контролируем кол-во создаваемых экземпляров, что не есть гуд. Поэтому мне нужно в потомке, будь то *Collection или Rewrites задать настройку: синглтон это или можно много экземпляров создавать. И в этой теме я спрашиваю народ: как же лучше эту настройку сделать? Пока идея это сделать в виде статической переменной, которой нет в родителе. Если она !isset или false - одноинстанционный, в противном случае - мульти.
Лучше не делать настройку. Не наследуй Синглтон... вообще. Сделай шаблон класса Синглтон, и создавай на его базе сколько угодно путем правки кода! но не наследования!
Simpliest идею понял. Но что тут плохого? я же по сути предлагаю отказ от избыточности, повторяющегося куска кода.
блин сперва вроде понял про синглтон, но потом опять запутался.... Поэтому оффтопом спрошу: Кос, чесно говоря класс Юзер просто жесть. Если не секрет зачем там юзерсы? И еще вопрос ко всем: че за прикол писать $this->db = Database::getInstance(); Это чтобы потом короче было $this->db->query? Че ссылки то плодить?
Users - для всех пользователей. User - для текущего пользователя, который этот скрипт запускает. Его паблик методы: статические, но могут быть запущены и через полученную инстанцию isAuthenticated isAdmin (включает проверку на аутентификацию) isRoot logIn($name, $pass, $asAdmin = false) (пытается залогиниться под посланными параметрами. Если че не так - бросает искл.) logOut getBaseInfo($field = NULL) (возвращает всякие параметры типа логина, мыла и тд) опять статические getPermissions getGroups checkPermission($permission) checkResource($resource, $resourceId) value($field) (похоже на getBaseInfo, но это не базовые параметры а опциональные, которые через UsersFields создаются) User работает через Users, просто нам не нужно знать или указывать ID текущего юзера. PHP: <? // ... public static function getPermissions() { return self::instance()->users->getPermissions(self::instance()->userId); } public static function getGroups() { return self::instance()->users->getGroups(self::instance()->userId); } public static function checkPermission($permission) { return self::instance()->users->checkPermission($permission, self::instance()->userId); } public static function checkResource($resource, $resourceId) { return self::instance()->users->checkResource($resource, $resourceId, self::instance()->userId); } public static function value($field) { return UsersManager::instance()->value(self::instance()->userId, $field); } // ... Переменные в методах меняются местами и скачут как потерпевшие. Я в курсе. ну типа того. А это плохо?
пока суть да дело, у нас появилась такая вот какашенция: PHP: <?php abstract class Creators { /** * @var array array of class instances **/ protected static $instances = array(); final private function __clone() {} final private function createClass($class, $params) { if ($params) { $reflection = new ReflectionClass($class); return $reflection->newInstanceArgs($params); } else { return new $class(); } } final public static function instance($id = 'default', $params = NULL) { $class = get_called_class(); if (isset(self::$multi)) { if (self::$multi) { return (isset(self::$instances[$class][$id])) ? self::$instances[$class][$id] : self::$instances[$class][$id] = self::createClass($class, $params); } } else { return (isset(self::$instances[$class])) ? self::$instances[$class] : self::$instances[$class] = self::createClass($class, $params); } } } if (!function_exists('get_called_class')): //TODO:find another analog function get_called_class() { $bt = debug_backtrace(); $lines = file($bt[1]['file']); preg_match( '/([a-zA-Z0-9\_]+)::' . $bt[1]['function'] . '/', $lines[$bt[1]['line']-1], $matches); return $matches[1]; } endif; @@ -1,6 +1,6 @@ -abstract class UsersCommon +abstract class UsersCommon extends Creators @@ -42,5 +42,5 @@ - final private function __clone() {} + protected static $multi = false; несмотря на отговоры товарища из Донецка, в тестовом режиме сделал. Посмотрю: будет ли какое-то удобство от этой какашки или нет. Один черт это идет коммитом и я смогу откатиться если что-то пойдет не так.
ну не знаю. Вообще привожу свои примеры: PHP: <?php class User extends KTF_Object { /** * @var array */ private static $_UserObjectsPool = array(); public function __construct($UserId = NULL) { parent::_SetKeyField('id', KTF_Db::KTF_Db_Format_Int, $UserId); parent::_SetTableName(USER_MAIN_TABLE); parent::_AddMainProperty('Id', 'id', KTF_Db::KTF_Db_Format_Int); parent::_AddMainProperty('Login', 'login', KTF_Db::KTF_Db_Format_Str); parent::_AddLazyProperty('Password', USER_MAIN_TABLE, 'pswd'); parent::_AddLazyProperty('Email', USER_MAIN_TABLE, 'email'); } //...... /** * @static * @param in $UserId * @return User */ public static function GetInstance($UserId = NULL) { if(!$UserId) { return new User(NULL); } $UserUdentifiers = self::GetIdentifiers(); if(isset($UserUdentifiers[$UserId])) { if(isset(self::$_UserObjectsPool[$UserId])) { return self::$_UserObjectsPool[$UserId]; } else { self::$_UserObjectsPool[$UserId] = new User($UserId); return self::$_UserObjectsPool[$UserId]; } } else { return new User(NULL); } }