Foros del Web » Programando para Internet » PHP » Frameworks y PHP orientado a objetos »

Clase que admite crear varias instancias o sólo una (patrón Singleton)

Estas en el tema de Clase que admite crear varias instancias o sólo una (patrón Singleton) en el foro de Frameworks y PHP orientado a objetos en Foros del Web. Hola, Estoy empezando a jugar con la programación orientada a objetos y me preguntaba que opina la gente sobre el siguiente código: Código PHP: <?php ...
  #1 (permalink)  
Antiguo 10/05/2012, 12:56
Avatar de Ronin46  
Fecha de Ingreso: junio-2009
Mensajes: 398
Antigüedad: 15 años, 4 meses
Puntos: 8
Pregunta Clase que admite crear varias instancias o sólo una (patrón Singleton)

Hola,

Estoy empezando a jugar con la programación orientada a objetos y me preguntaba que opina la gente sobre el siguiente código:

Código PHP:
<?php
abstract class Clase_Base
{
    protected 
$Variable;
    
    protected function 
__construct ()
    {
        echo 
'<p>Constructor Clase_Base</p>';
    }
    
    public function 
set_Variable ($Valor) { $this->Variable $Valor; }
    public function 
get_Variable () { echo '<p>Variable: ' $this->Variable '</p>'; }
}

abstract class 
Clase_Base_Singleton extends Clase_Base
{
    private static 
$Instancia;
    private static 
$NInstancias;
    
    protected function 
__construct ()
    {
        
self::$NInstancias 0;
        echo 
'<p>Constructor Clase_Base_Singleton</p>';
        
parent::__construct();
    }
    
    public static function 
singleton($Tabla)
    {
        if (!isset(
self::$Instancia))
        {
            echo 
'Singleton';
            
self::$Instancia = new $Tabla;
        }
        
self::$NInstancias++;
        return 
self::$Instancia;
    }
}

class 
Mi_Clase extends Clase_Base_Singleton
{
    public function 
__construct ()
    {
        echo 
'<p>Constructor Mi_Clase</p>';
        
parent::__construct();
    }
}

$Clase1 Mi_Clase::singleton('Mi_Clase');
$Clase1->set_Variable('variable singleton');
$Clase1->get_Variable(); // imprime "variable singleton"

$Clase2 Mi_Clase::singleton('Mi_Clase');
$Clase2->get_Variable(); // imprime "variable singleton"

$Clase3 = new Mi_Clase;
$Clase3->get_Variable(); // No imprime nada
$Clase3->set_Variable('variable');
$Clase3->get_Variable(); // Imprime "variable"

$Clase4 = new Mi_Clase;
$Clase4->get_Variable(); // No imprime nada

$Clase5 Mi_Clase::singleton('Mi_Clase');
$Clase5->get_Variable(); // imprime "variable singleton"
?>
¿Veis bien el hecho de que una clase permita la creación de varias instancias o una única (singleton) según se desee? ¿Qué problemas le veis?

Saludos.
__________________
http://www.controldegastos.com, acepto sugerencias para el sitio.
Repetir conmingo: "tengo que dedicar más tiempo a gozar de placer"

Última edición por Ronin46; 10/05/2012 a las 12:58 Razón: Cambio de título
  #2 (permalink)  
Antiguo 10/05/2012, 16:19
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 18 años, 5 meses
Puntos: 2135
Respuesta: Clase que admite crear varias instancias o sólo una (patrón Singleton)

Personalmente estoy muy en contra de Singleton, luego lo que pretendes hacer, quedaría mejor con un patrón Registry (que tampoco me gusta nada).
  #3 (permalink)  
Antiguo 10/05/2012, 16:28
Avatar de masterpuppet
Software Craftsman
 
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 3.550
Antigüedad: 16 años, 10 meses
Puntos: 845
Respuesta: Clase que admite crear varias instancias o sólo una (patrón Singleton)

Singletons , para lo que quieres alguna suerte de Identity Map da y sobra.

Saludos.
__________________
http://es.phptherightway.com/
thats us riders :)
  #4 (permalink)  
Antiguo 11/05/2012, 11:11
Avatar de Ronin46  
Fecha de Ingreso: junio-2009
Mensajes: 398
Antigüedad: 15 años, 4 meses
Puntos: 8
Respuesta: Clase que admite crear varias instancias o sólo una (patrón Singleton)

Gracias a los dos,

Entiendo por vuestras respuestas, que correcto es, otra cosa es que haya formas mejores o "guerras santas" de por medio.
Así pues creo que estaría bien tener esa estructura para cualquier clase, con lo cual las clases que hereden de dichas clases base pueden ser Singleton o no con tan sólo cambiar la línea de código que crea el objeto.

En cuanto al patrón Registry creo que no me vale para lo que busco con las clases que puse pero me viene bien para otra cosa a la que precisamente le estaba dando vueltas y que buscando por el foro qué era el patrón Registry me encontré justo con lo que necesitaba.
Básicamente simplificando mucho es como un contenedor de variables globales, que si haces que sus funciones sean estáticas ni tienes que instanciarlo.

Y por lo que que vi del Identity Map creo que es algo que por lo de ahora se aleja de lo que busco, pero está bien saberlo porque a medida que me vaya adentrando y me vayan surgiendo otras necesidades igual si tiene utilidad.

Saludos.
__________________
http://www.controldegastos.com, acepto sugerencias para el sitio.
Repetir conmingo: "tengo que dedicar más tiempo a gozar de placer"
  #5 (permalink)  
Antiguo 11/05/2012, 13:45
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 18 años, 5 meses
Puntos: 2135
Respuesta: Clase que admite crear varias instancias o sólo una (patrón Singleton)

Pues correcto no es, cuando hablas de "contenedor de variables globales" estas rompiendo con todo lo que es Programación Orientada a Objetos.

Si quieres hacer algo así, mejor tira de global y te evitas hacer todo eso...

Una cosa como dices tú es que "funciona" pero una vez que te adentres mucho más vas a ver más los problemas en lo que estas haciendo.

Mejor como te digo investiga sobre DI, vas a ver un nuevo mundo, y realmente vas a entender como debes de usar POO.
  #6 (permalink)  
Antiguo 11/05/2012, 15:13
Avatar de Ronin46  
Fecha de Ingreso: junio-2009
Mensajes: 398
Antigüedad: 15 años, 4 meses
Puntos: 8
Respuesta: Clase que admite crear varias instancias o sólo una (patrón Singleton)

Cita:
Pues correcto no es, cuando hablas de "contenedor de variables globales" estas rompiendo con todo lo que es Programación Orientada a Objetos.
Lo de correcto iba por el código que puse, y lo del "contenedor global de variables globales" iba por la posible aplicación que le vi al Registry.

En cuanto a la inyección de dependencias es algo que tenía visto pero me parece un poco rollo tener que andar a pasar siempre las dependencias que necesito, eso si puedo, porque hay veces que no es posible.

Cita:
Una cosa como dices tú es que "funciona" pero una vez que te adentres mucho más vas a ver más los problemas en lo que estas haciendo.
En esa fase estoy, en la de aprender, o lo que es lo mismo, hacer cosas que "funcionan" pero que luego miro que a la hora de mantener el código se vuelven un problema y por lo tanto tengo que ver otras formas de hacer las cosas.

El principal problema con el que me estoy aplicando es que cada cual tiene su propia filosofía de POO (y bastante diferentes unas de otras), por lo que es un poco difícil sacar cosas en claro.

Al final no es más que una herramienta que cada cual usa como le conviene, y mientras su método le vaya bien (aunque no sea lo que se estile) y sea productivo no hay problema.
__________________
http://www.controldegastos.com, acepto sugerencias para el sitio.
Repetir conmingo: "tengo que dedicar más tiempo a gozar de placer"
  #7 (permalink)  
Antiguo 11/05/2012, 16:10
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 18 años, 5 meses
Puntos: 2135
Respuesta: Clase que admite crear varias instancias o sólo una (patrón Singleton)

Pues no es que haya filosofías, más bien existen lo que se llama patrones de diseño, que precisamente son como "recetas" que te ayudan a implementar una solución a un problema en específico usando una solución genérica.

Te recomiendo mejor estudies los patrones de diseño y trates de adaptarte lo más posible patrones como MVC, cosas así, ya que si empiezas a usar lo que piensas que es lo más correcto, puede que no sea lo más correcto, menos cuando vienes de programación orientada a funciones.
  #8 (permalink)  
Antiguo 11/05/2012, 18:31
Avatar de Ronin46  
Fecha de Ingreso: junio-2009
Mensajes: 398
Antigüedad: 15 años, 4 meses
Puntos: 8
Respuesta: Clase que admite crear varias instancias o sólo una (patrón Singleton)

Pero al final, por muchos patrones de diseño que haya, con un sólo patrón de diseño se pueden arreglar "todos" los problemas, otra cosa es el camino que tengas que seguir para adaptar ese patrón a ese problema (o ese problema a ese patrón).

Por ejemplo, una conexión a la base de datos, hay gente que aplica el patrón Registry, otros Singleton, otros inyección de dependencias... y mientras resuelvan su problema concreto es suficiente.
Si no van a necesitar conectarse a dos bases de datos usarán un singleton por ejemplo, en vez de inyección de dependencias. Me podrás decir, pero si usas inyección de dependencias estás siendo previsor para el día que si necesites trabajar contra más de una base de datos, si, cierto, pero andar a pensar en el futuro si aun no has acabado el presente.... no necesariamente es bueno...

Bueno, tampoco pretendo crear discusión, al fin y al cabo este tipo de discusiones ya están más que manidas, simplemente quería saber si el código con el que estoy trasteando esta bien en cuanto a POO se refiere o si es una burrada (a pesar de que funciona).

Al final le he dado un par de vueltas a las clases que puse previamente y llegué a esto:
Código PHP:
<?php
abstract class Clase_Base
{
    protected function 
__construct ()
    {
        echo 
'<p>Constructor Clase_Base</p>';
    }
}

abstract class 
Clase_Base_Singleton extends Clase_Base
{
    private static 
$Instancia = array();
    private static 
$NInstancias = array();
    private static 
$ModoSingleton = array();
    
    protected function 
__construct ($Clase)
    {
        if (!isset(
self::$ModoSingleton[$Clase]) || (isset(self::$ModoSingleton[$Clase]) && self::$ModoSingleton[$Clase] === FALSE))
        {
            
self::$ModoSingleton[$Clase] = FALSE;
            
self::$NInstancias[$Clase] = 1;
            echo 
'<p>Constructor Clase_Base_Singleton</p>';
            
parent::__construct();
        }
        else
        {
            echo 
"<p><b>Clase ya instanciada en modo singleton</b></p>";
        }
    }
    
    public static function 
singleton($Clase)
    {
        if (!isset(
self::$ModoSingleton[$Clase]))
        {
            echo 
'<p>Singleton</p>';
            
self::$Instancia[$Clase] = new $Clase;
            
self::$ModoSingleton[$Clase] = TRUE;
            
self::$NInstancias[$Clase] = 0;
        }
        
        if (isset(
self::$ModoSingleton[$Clase]) && self::$ModoSingleton[$Clase] === TRUE)
        {
            
self::$NInstancias[$Clase]++;
            return 
self::$Instancia[$Clase];
        }
        else
        {
            echo 
'<p><b>Clase ya instanciada en modo no singleton</b></p>';
        }
    }
    
    public function 
get_NInstancias($Clase) { echo '<p>NInstancia: ' self::$NInstancias[$Clase] . '</p>'; }
}

class 
Mi_Clase extends Clase_Base_Singleton
{
    public function 
__construct ()
    {
        echo 
'<p>Constructor Mi_Clase</p>';
        
parent::__construct('Mi_Clase');
    }
}

class 
Mi_Clase2 extends Clase_Base_Singleton
{
    public function 
__construct ()
    {
        echo 
'<p>Constructor Mi_Clase2</p>';
        
parent::__construct('Mi_Clase2');
    }
}

echo 
'<p><b>Singleton</b></p>';
$Clase1 Mi_Clase::singleton('Mi_Clase');
$Clase1->get_NInstancias('Mi_Clase');

echo 
'<p><b>Singleton</b></p>';
$Clase2 Mi_Clase::singleton('Mi_Clase');
$Clase2->get_NInstancias('Mi_Clase');

echo 
'<p><b>Singleton</b></p>';
$Clase3 Mi_Clase::singleton('Mi_Clase');
$Clase3->get_NInstancias('Mi_Clase');

echo 
'<p><b>Normal</b></p>';
$Clase4 = new Mi_Clase;

echo 
'<p><b>Normal</b></p>';
$Clase5 = new Mi_Clase2;
$Clase5->get_NInstancias('Mi_Clase2');

echo 
'<p><b>Normal</b></p>';
$Clase6 = new Mi_Clase2;
$Clase6->get_NInstancias('Mi_Clase2');

echo 
'<p><b>Normal</b></p>';
$Clase7 = new Mi_Clase2;
$Clase7->get_NInstancias('Mi_Clase2');

echo 
'<p><b>Singleton</b></p>';
$Clase8 Mi_Clase::singleton('Mi_Clase2');
?>
Que produce como salida

Código HTML:
Singleton

Singleton

Constructor Mi_Clase

Constructor Clase_Base_Singleton

Constructor Clase_Base

NInstancia: 1

Singleton

NInstancia: 2

Singleton

NInstancia: 3

Normal

Constructor Mi_Clase

Clase ya instanciada en modo singleton

Normal

Constructor Mi_Clase2

Constructor Clase_Base_Singleton

Constructor Clase_Base

NInstancia: 1

Normal

Constructor Mi_Clase2

Constructor Clase_Base_Singleton

Constructor Clase_Base

NInstancia: 1

Normal

Constructor Mi_Clase2

Constructor Clase_Base_Singleton

Constructor Clase_Base

NInstancia: 1

Singleton

Clase ya instanciada en modo no singleton
De esta forma consigo que cualquier clase que cree pueda ser inicializada en modo singleton o no según me apetezca.
__________________
http://www.controldegastos.com, acepto sugerencias para el sitio.
Repetir conmingo: "tengo que dedicar más tiempo a gozar de placer"
  #9 (permalink)  
Antiguo 11/05/2012, 19:10
Avatar de carlos_belisario
Colaborador
 
Fecha de Ingreso: abril-2010
Ubicación: Venezuela Maracay Aragua
Mensajes: 3.156
Antigüedad: 14 años, 7 meses
Puntos: 461
Respuesta: Clase que admite crear varias instancias o sólo una (patrón Singleton)

bueno no voy a volver a indicarte lo que ya gatorV y master te hablaron del singleton, lo que voy a hablarte es un poco mas hacia ver lo que realizaste y ver cual es la finalidad, si ves el patrón singleton te indica que es de instancia unica es decir se usa cuando deseas que un objeto solo sea instanciado una vez y ninguna más, entonces para que aplicar este patrón a una clase que a lo mejor vas a necesitar mas instancias de este?? Ademas al hacer publico el contructor de la hija y poder hacer mas de una instancia del padre estas rompiendo con el patrón, los patrones aunque hayan los que no gusten como este son para seguirlos y hacer uso de su funcionalidad, saludos
__________________
aprende d tus errores e incrementa tu conocimientos
it's not a bug, it's an undocumented feature By @David
php the right way
  #10 (permalink)  
Antiguo 12/05/2012, 04:44
Avatar de Ronin46  
Fecha de Ingreso: junio-2009
Mensajes: 398
Antigüedad: 15 años, 4 meses
Puntos: 8
Respuesta: Clase que admite crear varias instancias o sólo una (patrón Singleton)

Hola Carlos, lo que planteas es la discusión que quería tener :)

Actualmente por cada clase que quiero que sea Singleton tengo que crearme la típica estructura de Singleton, o lo que es lo mismo, estoy repitiendo código en todas aquellas clases a instanciar en modo Singleton.

Lo que pretendo con el código que he puesto es tener una clase base (esto es, que cualquier clase va a heredar de esta clase base) a partir de la cual se le ofrece la posibilidad a las clases que heredan el comportarse en modo Singleton si así lo desean. De esta forma sólo tengo en un único sitio la estructura del Singleton, que me vale para cualquier clase.

Respecto a lo del constructor público de la hija efectivamente tienes razón, pero eso es lo que intento solventar manteniendo un array de clases instanciadas y verificando que una misma clase sólo se puede instanciar en modo Singleton o no.

Que me estoy cargando los principios del Singleton, pues vale, llamemos a esto de otra forma.

¿Se entiende lo que estoy persiguiendo?

Quizás sea más o menos lo mismo que implementar el patrón Registry que comentaba GatorV (pero con otro enfoque), ya que aquellas clases que quiero que tengan instancia única las podría almacenar en la clase Registry para recuperarlas allí donde necesite usarlas en lugar de preocuparme de si tengo que instanciarla en modo Singleton o no.

Saludos.

EDITO: No sé, quizás se asemeje al patrón Identiy Map que comentaba Masterpuppet. Al final supongo que la diferencia radica en que las clases que he diseñado soy capaz de visualizarlas mientras que el patrón Registry o Identity Map todavía no soy capaz de visualizarlos, pero eso será algo que vaya cambiando a medida que vaya viendo más cosas y me vayan surgiendo problemas a resolver.
__________________
http://www.controldegastos.com, acepto sugerencias para el sitio.
Repetir conmingo: "tengo que dedicar más tiempo a gozar de placer"

Última edición por Ronin46; 12/05/2012 a las 04:56
  #11 (permalink)  
Antiguo 12/05/2012, 13:20
Avatar de carlos_belisario
Colaborador
 
Fecha de Ingreso: abril-2010
Ubicación: Venezuela Maracay Aragua
Mensajes: 3.156
Antigüedad: 14 años, 7 meses
Puntos: 461
Respuesta: Clase que admite crear varias instancias o sólo una (patrón Singleton)

Bueno te voy a repetir como ya te han dicho el singleton no gusta a muchos (excepto por master que lo ama XD), hablando en serio fijate lo que te hablaba master sobre el identity map,
Cita:
Iniciado por martin fowler
Ensures that each object gets loaded only once by keeping every loaded object in a map. Looks up objects using the map when referring to them.
entonces lo más seguro es que este pattern te sirva, acá
tienes un ejemplo, saludos
__________________
aprende d tus errores e incrementa tu conocimientos
it's not a bug, it's an undocumented feature By @David
php the right way
  #12 (permalink)  
Antiguo 12/05/2012, 16:37
Avatar de GatorV
$this->role('moderador');
 
Fecha de Ingreso: mayo-2006
Ubicación: /home/ams/
Mensajes: 38.567
Antigüedad: 18 años, 5 meses
Puntos: 2135
Respuesta: Clase que admite crear varias instancias o sólo una (patrón Singleton)

Realmente creo que estas enfocando el problema muy muy mal, muchas veces se ha indicado el porque Singleton es un mal patrón, ya que la gente con poca experiencia en POO tiende a abusar de él, y es justamente lo que estas haciendo ahorita, abusando del patrón, aunque te "sirve" no es lo correcto.

Ahora, heredar todos tus objetos de un mismo objeto, es otro error catastrófico, recuerda los principios de polimorfismo.

Tienes que estudiar mucho, para precisamente tener principios fuertes antes de adentrarte más porque créeme, esto que estas haciendo tarde o temprano te va a venir a afectar cuando intentes escalar tu sistema (que precisamente son los beneficios de POO).

Sí no piensas en tu sistema para escalarlo, le estas quitando todo el beneficio de hacerlo en POO.
  #13 (permalink)  
Antiguo 13/05/2012, 05:31
Avatar de Ronin46  
Fecha de Ingreso: junio-2009
Mensajes: 398
Antigüedad: 15 años, 4 meses
Puntos: 8
Respuesta: Clase que admite crear varias instancias o sólo una (patrón Singleton)

Bueno, es evidente que no es ni mínimamente negociable lo que estoy intentando hacer

En cuanto a lo que se comenta del Identity Map efectivamente es lo que aparentemente necesito, al menos eso saco de la teoría, pero en estos momentos tengo un problema de visualización de su implementación, lo tendré que ver más detenidamente.

En estos momentos creo que tiraré por el patrón Registry, que soy capaz de visualizarlo. Ya sé que tampoco os gusta, pero poco a poco. Esto es como aprender a sumar, antes de hacer la suma mentalmente tienes que pasar por la fase de hacer la suma ayudándote de los dedos de la mano Y teniendo en cuenta que PHP (o POO a este nivel independientemente del lenguaje) es algo que miro en mis tiempos libres, los cuales tienden a 0, creo que estaré bastante tiempo en esta fase.

Y por supuesto que me falta mucho por aprender!

Gracias por vuestro tiempo y paciencia

EDITO: ¿Dónde está el icono para dar Karma?
__________________
http://www.controldegastos.com, acepto sugerencias para el sitio.
Repetir conmingo: "tengo que dedicar más tiempo a gozar de placer"

Última edición por Ronin46; 13/05/2012 a las 05:37

Etiquetas: admite, clase, class, objetos, php, singleton
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 11:34.