locked
Clase Estatica vs Patron Singleton RRS feed

  • Pregunta

  • Hola a todos,

    tengo claras las diferencias entre una clase estática o usar el patrón Singleton:

      - Una clase estática usa la memoria "stack" mientras que una clase implementada bajo el patrón singleton usa la memoria "heap".

      - Una clase estática se carga al principio del programa y se le asigna un memoria estática mientras que una clase singleton se carga la primera vez que se requiera su uso y se guarda en la memoria dinámica.

      - La clase singleton sigue los OOP (object oriented principles) y por tanto puede implementar una interfaz, su instancia puede ser pasada como parámetro a otro método, etc.

    Pero mi duda es, cuando no se necesite ninguna característica propia de los objetos (implementar interfaz, etc) y funcionalmente nos sirva tanto la clase estática como el patrón songleton (pues funcionalmente no encuentro diferencia alguna entre ellas)... ¿Qué opción es mejor?

    Si no he entendido mal, la clase estática da un mayor rendimiento al ser su acceso a memoria más rápido (aunque es casi insignificante) pero no hay que perder de vista que estamos gastando recursos de memoria... También tengo la hipotesis de que una clase estática es mejor para el caso en el que, en una aplicación multithread, varios hilos hagan uso de los métodos declarados dentro de la clase (pero no sé con certeza si es así)...

    Espero que alguien pueda ayudarme porque por más que busco por ahí no saco nada en claro.

    Un saludo y gracias de antemano.

    viernes, 11 de octubre de 2019 6:15

Respuestas

  • Hay algún error en lo que comentas.

    La clase estática no usa la memoria "stack". No hay que instanciarla, sus variables ocupan memoria permanentemente en el segmento de datos, sin usar ni el stack ni el heap. Otra cosa es que alguno de sus métodos asigne variables locales, en cuyo caso irían al stack, tanto si la clase es estática como si no lo es. Y lo mismo si se hace un "new" de alguna variable interna tipo-referencia de la clase: siempre irá al heap, tanto si la clase es estática como si no.

    Lo de que la clase estática "se carga" al principio del programa depende de qué entiendas por "cargarla". Si te refieres a que se ejecute el constructor estático, entonces no necesariamente es así. A partir del Framework 4.5, hay una optimización que hace que el constructor de la clase estática no se ejecute mientras no se haga ninguna llamada a la clase. Desde este punto de vista, no se carga desde el principio. Y si te refieres a que el JIT cargue en memoria el código compilado, la clase estática se comporta igual que las no-estáticas: no se JIT-compila ningún método hasta que es invocado. Luego desde este punto de vista, tampoco se "carga" desde el principio.

    En cuanto a "cuál es mejor": el tema de la velocidad de acceso a memoria no es significativo. La clase estática no pierde tiempo en instanciarse (una única vez si usas el patrón singleton), pero esto tampoco suele ser significativo. Es un poco más sencillo escribirla, porque no tienes que implementar el singleton, y es un poco más sencillo llamarla, porque la invocas por su nombre sin tener que llamar al método que devuelve la instancia y conservar la referencia que te devuelve en una variable.

    En resumidas cuentas, es un poco más sencillo programar usando la clase estática. Esto lleva a veces a que se abuse de ellas. La limitación que tiene la clase estática es que no puedes usar los mecanismos normales de inyección de dependencias para inyectarla en el código, lo cual dificulta la escritura de las pruebas unitarias.

    viernes, 11 de octubre de 2019 6:45
    Moderador
  • Primeramente, muchísimas gracias por tu respuesta, me has aclarado bastante bien lo del tema de la memoria y lo de "cargar" la clase, que estaba algo confundido.

    La conclusión a la que llegué fue que la mayor limitación que tiene la clase estática es el no poder usarla en la inyección de dependencias (al menos en la típica forma de inyectar la clase por el constructor). Pero claro, salvo para lo que tu comentas (las pruebas unitarias) no tiene ningún sentido usar la inyección de dependencias pues una clase estática es accesible desde cualquier parte y no es que te suponga un acoplamiento de ésta clase con el resto... ¿Estoy en lo cierto?

    Por lo tanto, si no se va a requerir de ninguna de las ventajas del singleton (implementar interfaz, inyección de depencias para pruebas unitarias, etc) veo indiferente usar una clase estática o una con una instancia única (quizás la primera por ser menos compleja, pero a gusto del consumidor).

    Muchas gracias de nuevo.

    viernes, 11 de octubre de 2019 8:34

Todas las respuestas

  • Hay algún error en lo que comentas.

    La clase estática no usa la memoria "stack". No hay que instanciarla, sus variables ocupan memoria permanentemente en el segmento de datos, sin usar ni el stack ni el heap. Otra cosa es que alguno de sus métodos asigne variables locales, en cuyo caso irían al stack, tanto si la clase es estática como si no lo es. Y lo mismo si se hace un "new" de alguna variable interna tipo-referencia de la clase: siempre irá al heap, tanto si la clase es estática como si no.

    Lo de que la clase estática "se carga" al principio del programa depende de qué entiendas por "cargarla". Si te refieres a que se ejecute el constructor estático, entonces no necesariamente es así. A partir del Framework 4.5, hay una optimización que hace que el constructor de la clase estática no se ejecute mientras no se haga ninguna llamada a la clase. Desde este punto de vista, no se carga desde el principio. Y si te refieres a que el JIT cargue en memoria el código compilado, la clase estática se comporta igual que las no-estáticas: no se JIT-compila ningún método hasta que es invocado. Luego desde este punto de vista, tampoco se "carga" desde el principio.

    En cuanto a "cuál es mejor": el tema de la velocidad de acceso a memoria no es significativo. La clase estática no pierde tiempo en instanciarse (una única vez si usas el patrón singleton), pero esto tampoco suele ser significativo. Es un poco más sencillo escribirla, porque no tienes que implementar el singleton, y es un poco más sencillo llamarla, porque la invocas por su nombre sin tener que llamar al método que devuelve la instancia y conservar la referencia que te devuelve en una variable.

    En resumidas cuentas, es un poco más sencillo programar usando la clase estática. Esto lleva a veces a que se abuse de ellas. La limitación que tiene la clase estática es que no puedes usar los mecanismos normales de inyección de dependencias para inyectarla en el código, lo cual dificulta la escritura de las pruebas unitarias.

    viernes, 11 de octubre de 2019 6:45
    Moderador
  • Primeramente, muchísimas gracias por tu respuesta, me has aclarado bastante bien lo del tema de la memoria y lo de "cargar" la clase, que estaba algo confundido.

    La conclusión a la que llegué fue que la mayor limitación que tiene la clase estática es el no poder usarla en la inyección de dependencias (al menos en la típica forma de inyectar la clase por el constructor). Pero claro, salvo para lo que tu comentas (las pruebas unitarias) no tiene ningún sentido usar la inyección de dependencias pues una clase estática es accesible desde cualquier parte y no es que te suponga un acoplamiento de ésta clase con el resto... ¿Estoy en lo cierto?

    Por lo tanto, si no se va a requerir de ninguna de las ventajas del singleton (implementar interfaz, inyección de depencias para pruebas unitarias, etc) veo indiferente usar una clase estática o una con una instancia única (quizás la primera por ser menos compleja, pero a gusto del consumidor).

    Muchas gracias de nuevo.

    viernes, 11 de octubre de 2019 8:34