Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





No Me Gustan Los Singletones

Iniciado por DraKKaR, 03 de Octubre de 2004, 12:27:43 PM

« anterior - próximo »

DraKKaR

 Primero veamos si lo he entendido todo bien. Un singleton es una clase de la que únicamente puede instanciarse un único objeto. La forma de hacerlo sería por ejemplo, que para instanciar de una clase haya que hacerlo a través de una función tal que así:


MiClase Instanciamela(void){
   static MiClase *obj=NULL;
   if (!obj)
       obj=new MiClase;
   return obj;
}


Bien, yo no digo que no sea interesante que, si de una clase sólo puede haber una instancia, recurrir a este truco para asegurarse de ello. Lo que realmente no me gusta es que, el programador que use este sistema, puede estar intentando instanciar más de una vez un objeto de este tipo (mediante esta función) sin saber que está obrando mal.

Pondré un ejemplo con Direct3D: soy un progamador que no tiene mucha idea y en mi programa intento llamar 3 veces a la función Direct3DCreate9. Si uso un singletón como el anterior, podré hacerlo sin problemas, simplemente la función creará sólo la primera vez el objeto y las otras veces me devolverá nua instancia a ese primer objeto. ¡Pero el programador no sabrá que lo que está haciendo está mal! Incluso como funciona el programador puede llegar a pensar que en realidad está instanciando 3 veces el objeto, pero en realidad solo lo ha hecho una vez.

Los singletones me parecen una forma de "engañar" al programador. Asumimos que el programador es estúpido y que intentará hacer cosas que no se deben hacer. Entonces, parece que la cuestión de los singletones sea:
"Dejemos que el programador escriba un mal programa, pero que en realidad funcione"!

Yo creo que una función que instancie un objeto, debería siempre instanciar un objeto de este tipo. Sin recurrir a trikiñuelas dentro de ella. Para intentar subsanar el error del programador "cliente".
Si un objeto sólo puede instanciarse una vez deberíaestar todo bien explicado en la documentación de la clase.

Veo mucho más útil reescribir la clase anterior de esta forma:

MiClase Instanciamela(void){
   static MiClase *obj=NULL;
   if (obj)
       throw ErrorDeLaMuerte;
   obj=new MiClase;
   return obj;
}


De esta forma el programador sabe que ha intentado hacer algo que está mal, al menos lógicamente y lo corregirá de la forma adecuada. Si se usa un singletón de la forma anterior, el pgroamador no sabe que lo que está intentando hacer (la idea que tiene en mente) está mal planteada o tiene algún problema de comprensión con la clase en cuestión.


Bueno, eso es lo que pienso. ¿Qué opinais? Si me ilumináis, pues mejor que mejor.

sés

 Pues te pongo una respuesta rápida:

Imagina la típica clase única (singleton) CVideo, encargada dibujar.

Suponemos que el programador solo instancia una vez CVideo para poder dibujar y hace algo como:
CVideo vid = new CVideo();
o
CVideo vid = CVideo::Instanciamela();

:) Bien, ese programador tiene su objeto único CVideo.

Pero... ¿qué pasa con las tropecientas funciones que pueden querer dibujar? ¿Cómo encuentran CVideo vid? ¿La pones en un .h para que el resto de clases la conozcan?

Según tu modelo las clases de la librería (que puede que ni sean tuyas) deben conocer tu variable, no solo la clase.
¿Qué pasaría si una clase externa llama antes a CVideo::Instanciamela()? Pues que ese programador "listo"sabrá que no puede instanciar otra vez CVideo... y además se quedará sin poder hacer nada :P

Espero que esto te aclare algo, no sé si lo expliqué bien :huh:
Soy indeciso... ¿o no?

DraKKaR

 ses:
Eso se arreglaría con dos funciones estáticas (de clase):


CVideo *CVideo::Instanciamela();
CVideo *CVideo::Damela();


Una instanciaría un nuevo objeto de la clase, y otra función simplemente lo devolvería.

La cuestión es que la función Instanciamela no "engañe" al programador haciendo creer que va a instanciar un objeto de esa clase, cuando sólo lo instanciará la primera vez que la llames. Las otras simplemente lo devolverá.

ethernet

 Umh, cuando usas un singleton es porque quieres solo una instancia de un objeto. Creo que deberías leer un poco más acerca del pattern Singleton y enterarte bien de para qué sirve. sés te ha dado una pista.
Además eso que has puesto NO es un singleton, un singleton sería esto:


class MyClass
{
private:

MYClass(){}
public:

static MyClass& Get(){ static MyClass h; return h;}
};


Así es imposible crear una instancia de MyClass.
Creo que tú lo que buscas es una variable global XD


sés

 
Cita de: "DraKKaR"Eso se arreglaría con dos funciones estáticas (de clase):


CVideo *CVideo::Instanciamela();
CVideo *CVideo::Damela();


¿Según eso tendrías que hacer algo así?
CVideo vid = CVideo::Instanciamela();
if( !vid ) vid = CVideo::Damela();

Uhm... no le veo la ventaja.

Creo que, como dice ethernet, lo más parecido a lo que buscas es una variable global.

Ahora se me ocurre otra cosa. Quizás te sirva algo del tipo:
Class CVideo {
  static CVideo *instance = NULL;
  static const int secretCode = 53452345;

  CVideo( int code=0 )
  {
     if( code != secretCode ) {
        // lanzar EXCEPCIONQUETECAGAS
     }
  }

public:
  CVideo getInstance() {
     if( !instance ) instance = new CVideo( secretCode );
     return instance;
  }  
}



Así, si alguien intenta nacer un new CVideo(), le da un pete del copón.
El que llame a CVideo::getInstance() evidentemente tiene que saber que es un singleton. Si no lo sabe, mal vamos.
Soy indeciso... ¿o no?

BeRSeRKeR

 Utilizando la forma de singleton que ha puesto ethernet, el usuario no podrá crear una instancia de la clase ya que el constructor es privado por lo que el compilador le lanzará un error. Sólo podrá acceder a la única instancia creada por el singleton.

Saludos.
¡Si te buscan en nombre de la ley, huye en nombre de la libertad!!

ethernet

 No creo que se trate de secrets code ni nada así. Cuando haces un singleton hay dos cosas importantes:
1.- sabes que es un singleton y el coder que lo usa lo sabe
2.- sabes que va a ser un pattern lazy (tal cual lo hemos definido antes) con lo cual hay que saber qué clases pueden ser singletonizadas y cuales no.

Si quieres ver un singleton puedes ir COTW! (http://www.stratos-ad.com/forums/index.php?act=ST&f=28&t=1771 ) en el que hay una discusión bastante interesante
tb en el cotd de flipcode: http://www.flipcode.com/cgi-bin/msg.cgi?sh...orum=cotd&id=-1

sés

 No estoy muy fino en estos temas, pero leí por ahí que el modelo que ha puesto ethernet no es bueno. Supongo que en algunos casos sirve, pero en otro no.
La principal razón que daban era que el objeto se construye siempre, aunque nadie lo quiera utilizar.
Soy indeciso... ¿o no?

ethernet

 Cual de todos los modelos? El que puse antes es lazy, no sé a qué te refieres.
De todas maneras por ahí iban los tiros cuando decía que hay que saber qué clases pueden ser usadas con ese tipo de singletones.

saludos

CoLSoN2

 Ante el ejemplo de ethernet de usar una variable static estática dentro del método ::get(), debo decir que tiene uninconveniente:

Yo antes usaba ese método porque me parecía más limpio, pero en modo Release (en Debug no) la aplicación me hacía cosas rarísimas, y después de mucho investigar lo que ocurría es que la variable static (static instancia; return instancia;) se creaba varias vecess (¿?). Igual era porque la aplicación usa threads o vete a saber qué, pero lo cambie a un atributo static (y dinámico, para poder destruirlo cuando quiera) de la clase, y listo.
Manuel F. Lara
Descargar juegos indie  - blog sobre juegos indie y casual
El Desarrollo Personal.com  - blog sobre productividad, motivación y espíritu emprendedor

Mars Attacks

 @Drakkar: No Me Gustan Los Singletones

Pues apártalos y cómete las patatas.

ethernet

Cita de: "CoLSoN2"Ante el ejemplo de ethernet de usar una variable static estática dentro del método ::get(), debo decir que tiene uninconveniente:

Yo antes usaba ese método porque me parecía más limpio, pero en modo Release (en Debug no) la aplicación me hacía cosas rarísimas, y después de mucho investigar lo que ocurría es que la variable static (static instancia; return instancia;) se creaba varias vecess (¿?). Igual era porque la aplicación usa threads o vete a saber qué, pero lo cambie a un atributo static (y dinámico, para poder destruirlo cuando quiera) de la clase, y listo.
precisamente por eso odio los singletones, por los problemas de ese tipo, singletones SUCKSSS  

CoLSoN2

Cita de: "ethernet"
precisamente por eso odio los singletones, por los problemas de ese tipo, singletones SUCKSSS
pero como he dicho, eso tiene solución.
Manuel F. Lara
Descargar juegos indie  - blog sobre juegos indie y casual
El Desarrollo Personal.com  - blog sobre productividad, motivación y espíritu emprendedor

ethernet

 querido colsy, en esta vida todo tiene solución menos la muerte

DraKKaR

 Bueno, gracias a todos por las respuestas. Lo meditaré más profundamente a ver donde podría poner un singletón y si "me gusta como keda" XD.

Suopngo ke la calse principal del motor, de la que solo debería haber una isntancia, podría ser un buen ejemplo.






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.