¿Podría un tipo singleton reemplazar métodos y clases estáticas? [duplicar]

15

En C # Los métodos estáticos han tenido un propósito que nos permite llamarlos sin instanciar clases. Solo en el último año nos hemos vuelto más conscientes de los problemas de usar clases y métodos estáticos.

  • No pueden usar interfaces
  • No pueden usar la herencia
  • Son difíciles de probar porque no puedes hacer burlas y talones

¿Hay una mejor manera? Obviamente, debemos poder acceder a los métodos de la biblioteca sin clases de instancias todo el tiempo, de lo contrario nuestro código se volvería bastante abarrotado

Una posible solución es usar una nueva palabra clave para un concepto antiguo: the singleton . Los Singleton son instancias globales de una clase, ya que son instancias que podemos usar como lo haríamos con las clases normales. Sin embargo, para hacer su uso agradable y práctico, necesitaríamos un poco de azúcar sintáctica.

Diga que la clase de Matemáticas sería de tipo singleton en lugar de una clase real. La clase real que contiene todos los métodos predeterminados para el singleton matemático es DefaultMath, que implementa la interfaz IMath. El singleton se declararía como

singleton Math : IMath
{
   public Math
   {
      this = new DefaultMath();
   }
}

Si quisiéramos sustituir nuestra propia clase para todas las operaciones matemáticas, podríamos crear una nueva clase

MyMath que hereda DefaultMath , o simplemente podemos heredar de la interfaz IMath y crear una Clase completamente nueva. Para hacer que nuestra clase sea la clase de Matemáticas activa, harías una tarea simple

Math =  new MyMath();

y voilá! La próxima vez que llamemos a Math.Floor llamará a tu método. Tenga en cuenta que para un singleton normal tendríamos que escribir algo como Math.Instance.Floor pero el compilador elimina la necesidad de la propiedad Instance

Otra idea sería poder definir un singleton como perezoso para que se ejemplifiquen solo cuando se les llama por primera vez, como

lazy singleton Math : IMath

¿Qué crees que hubiera sido una mejor solución que las clases y los métodos estáticos? ¿Hay algún problema con este enfoque?

Addendum

Se han planteado algunos puntos, que uno de los principales beneficios de los métodos estáticos es tener métodos que son "sin estado" y, por lo tanto, libres de efectos secundarios, en cierta medida, desde el punto de vista de la concurrencia. Estoy totalmente de acuerdo en que ese es un punto válido. Sin embargo, estamos mezclando dos problemas y problemas diferentes aquí: uno es hacer que algunos métodos sean invocables y accesibles globalmente sin tener que crear explícitamente una instancia. El otro es tener métodos que son apátridas.

El segundo problema podría resolverse con un método que tenga algo así como una palabra clave sin estado que, de manera similar a la estática, les impidiera llamar a esto o quizás incluso más para no aplicar efectos secundarios. Con singletons en lugar de clases estáticas y algo así como clases y métodos sin estado, creo que tendrías los siguientes pros y contras

Pro's

  • Métodos "estáticos" en otras clases y clases marco podrían fácilmente ser diseñado para ser anulable
  • Las clases serían más fáciles de probar
  • Usar instancias en lugar de clases estáticas significa que los patrones de diseño funcionan mejor (cosas como fábricas)
  • Sin limitación de herencia y polimorfismo en contraste con la estática

Cons

  • ¿Quizás un rendimiento ligeramente peor?
  • Los programadores malos lo harán, pero todo en Singletons para tenerlos accesibles globalmente en lugar de usar la inyección de dependencia, tal vez solo debería poder acceder a los métodos de Singleton y no a propiedades / campos para evitar variables globales :)
  • ?

Tal vez Math fue un mal ejemplo, pero imagina que si los métodos de cadena .Net fueran ineficientes, podrías reemplazarlos fácilmente con los tuyos usando este método. O alguna clase de terceros tiene un método de singleton que quisieras alterar ligeramente, podrías heredar y alterar ese método

    
pregunta Homde 10.03.2011 - 14:06

3 respuestas

15

No hay diferencia en los peligros al cambiar sus métodos estáticos a métodos de instancia en un singleton. Son efectivamente los mismos.

A veces simplemente tienes funciones. Una función en términos matemáticos, no contiene ningún estado. Son simplemente los cálculos que se aplican a una entrada para determinar su salida. Por ejemplo, Math.Sqrt no contiene ningún estado. Realiza un cálculo en el valor que proporciona y devuelve una respuesta que se deriva de ese valor. En C, C ++, Ruby, Perl y otros lenguajes que admiten funciones simples, no tiene que vincular esa función a ninguna clase, estática o de otro tipo. En Java y C #, todas las funciones deben estar vinculadas a alguna clase, lo que técnicamente es un hack.

Es importante tener en cuenta que las funciones verdaderas están perfectamente bien para seguir siendo un método estático. Por ejemplo, todo en la clase Math está correctamente definido. No me apetece hacer algo estúpido como Math.Instance.Sqrt(x) solo para satisfacer un estándar de "no método estático".

La verdad es que su propiedad Instance en este caso sería el tipo de método estático que causa la mayoría de los problemas. ¿La razón? No es una función, mantiene el estado y cambia su comportamiento en función del estado interno. En el primer acceso, determina que la instancia global no existe, por lo que la crea. En accesos posteriores reutiliza esa instancia. En entornos de subprocesos múltiples, esto puede crear una condición de carrera que potencialmente puede crear múltiples instancias de la clase Math . Eventualmente, uno ganará y permanecerá almacenado, mientras que los otros recogerán la basura. Con la clase Math , la condición de carrera sería simplemente una ineficiencia asequible, pero si el singleton es necesario para mantener el estado de todos sus clientes, eso será un problema. Si agrega lock s alrededor del acceso de singleton, ha introducido un importante cuello de botella de rendimiento para las aplicaciones de subprocesos múltiples que solo empeora con el número de subprocesos. Esto es particularmente porque el bloqueo solo es necesario hasta que se crea la instancia.

Deje que sus funciones estén lo más cerca posible de las funciones, y nunca tendrá que preocuparse por estos problemas singleton de múltiples subprocesos. En lenguajes que soportan funciones, implementarlos como funciones. En los idiomas que requieren un método estático, conviértalos en un método estático. Singletons presenta una serie de problemas que solo salen a la luz cuando profundiza en su proyecto.

    
respondido por el Berin Loritsch 10.03.2011 - 15:43
5

Si la pregunta es "¿Qué usamos para reemplazar las clases estáticas?"

Singletons no son la respuesta.

Inyección de dependencia es.

Dicho esto, estoy usando singletons para reemplazar las clases estáticas en una base de código heredado, en este caso es mucho más factible realizar este cambio que agregar DI, y nos permite probar el código antiguo mucho más rápido. Consulte este pregunta de desbordamiento de pila para más información sobre esto

Actualizar
P1: ¿Cómo utilizaría la inyección de dependencia en un nivel de marco para cosas como las funciones de Matemáticas y Archivos?

¿A nivel de marco? Ya que se nos permite agregar soporte de idioma para Singleton , en cambio, agregamos soporte en el marco para DI en espacios de nombres como Matemáticas, IO, etc.
La configuración de la máquina proporcionará secciones que, de manera predeterminada, agregan los sabores de marco de estos, enlaces que podemos eliminar en los archivos app.config y agregamos en nuestros propios (u otros para pruebas)

P2: Además, si pudiera determinar qué clase usaría un singleton para diferentes clases, ¿no sería eso una inyección de dependencia de facto?

Suena confuso para mi compañero, así que en lugar de que su singleton represente un objeto único , ahora representa múltiples objetos y presenta otros diferentes según el contexto de cómo ¿llamado? ¿No sería a) convertirlo en un multipleton yb) ser una maldita pesadilla intentar y hacer un seguimiento de lo que cualquier método de Math dado va a hacer dependiendo de cómo / cómo lo llames?

    
respondido por el Binary Worrier 10.03.2011 - 14:19
0

La cuestión de interconectar y heredar clases estáticas también me mantuvo ocupada por un tiempo, aunque a nivel teórico más que práctico.

También hay un par de preguntas sobre SO que tratan el tema.

Finalmente encontré una solución que consiste esencialmente en

  • la separación de la parte "clase real" y la parte "clase estática" en 2 clases
  • un atributo de clase que asigna a una clase su clase pseudoestática
  • una clase auxiliar (estática) que recupera y crea una instancia de la clase pseudoestática para una clase

Para obtener más detalles, lea esta mini series en mi blog .

    
respondido por el devio 19.01.2012 - 21:11

Lea otras preguntas en las etiquetas