Cuándo usar clases estáticas en C #

Esto es lo que MSDN tiene que decir en Cuándo usar clases estáticas :

static class CompanyInfo { public static string GetCompanyName() { return "CompanyName"; } public static string GetCompanyAddress() { return "CompanyAddress"; } //... } 

Use una clase estática como unidad de organización para métodos no asociados con objetos particulares. Además, una clase estática puede simplificar y agilizar su implementación porque no tiene que crear un objeto para llamar a sus métodos. Es útil organizar los métodos dentro de la clase de una manera significativa, como los métodos de la clase Math en el espacio de nombres del sistema.

Para mí, ese ejemplo no parece abarcar muchos posibles escenarios de uso para clases estáticas. En el pasado, he usado clases estáticas para suites sin estado de funciones relacionadas, pero eso es todo. Entonces, ¿bajo qué circunstancias debería (y no debería) declararse estática una clase?

Escribí mis pensamientos sobre clases estáticas en una respuesta anterior de Desbordamiento de stack: clase con un solo método: ¿cuál es el mejor enfoque?

Solía ​​amar las clases de utilidad llenas de métodos estáticos. Hicieron una gran consolidación de los métodos de ayuda que, de otro modo, estarían alrededor causando redundancia y mantenimiento. Son muy fáciles de usar, sin creación de instancias, sin eliminación, solo olvídate. Creo que este fue mi primer bash involuntario de crear una architecture orientada a servicios: muchos servicios apátridas que simplemente hicieron su trabajo y nada más. Sin embargo, a medida que el sistema crece, vienen los dragones.

Polimorfismo

Digamos que tenemos el método UtilityClass.SomeMethod que alegremente suena. De repente, necesitamos cambiar la funcionalidad un poco. La mayor parte de la funcionalidad es la misma, pero tenemos que cambiar un par de partes, no obstante. Si no hubiera sido un método estático, podríamos hacer una clase derivada y cambiar el contenido del método según sea necesario. Como es un método estático, no podemos. Claro, si solo necesitamos agregar funcionalidad antes o después del método anterior, podemos crear una nueva clase y llamar a la anterior, pero eso es simplemente asqueroso.

Problemas de interfaz

Los métodos estáticos no se pueden definir a través de interfaces por razones lógicas. Y dado que no podemos anular los métodos estáticos, las clases estáticas son inútiles cuando necesitamos pasarlas por su interfaz. Esto nos impide usar clases estáticas como parte de un patrón de estrategia. Podríamos corregir algunos problemas pasando delegates en lugar de interfaces .

Pruebas

Esto básicamente va de la mano con los problemas de interfaz mencionados anteriormente. Como nuestra capacidad de intercambiar implementaciones es muy limitada, también tendremos problemas para reemplazar el código de producción con el código de prueba. Nuevamente, podemos envolverlos, pero requerirá que cambiemos partes grandes de nuestro código solo para poder aceptar envoltorios en lugar de los objetos reales.

Fosters blobs

Como los métodos estáticos se usan generalmente como métodos de utilidad y los métodos de utilidad generalmente tienen diferentes propósitos, rápidamente terminaremos con una gran clase llena de funcionalidades no coherentes; idealmente, cada clase debe tener un único propósito dentro del sistema. Prefiero tener cinco veces más clases siempre que sus propósitos estén bien definidos.

Parámetro creep

Para empezar, ese pequeño y lindo método estático e inocente podría tomar un solo parámetro. A medida que crece la funcionalidad, se agregan un par de nuevos parámetros. Pronto se agregan más parámetros que son opcionales, por lo que creamos sobrecargas del método (o simplemente agregamos valores predeterminados, en los idiomas que los admiten). En poco tiempo, tenemos un método que toma 10 parámetros. Solo los primeros tres son realmente necesarios, los parámetros 4-7 son opcionales. Pero si se especifica el parámetro 6, también se requieren rellenar 7-9 … Si hubiéramos creado una clase con el único propósito de hacer lo que este método estático hicimos, podríamos resolver esto tomando en cuenta los parámetros requeridos en el constructor, y permite al usuario establecer valores opcionales a través de propiedades o métodos para establecer múltiples valores interdependientes al mismo tiempo. Además, si un método ha crecido a esta cantidad de complejidad, lo más probable es que tenga que pertenecer a su propia clase.

Exige que los consumidores creen una instancia de clases sin ninguna razón

Uno de los argumentos más comunes es: ¿Por qué exigir que los consumidores de nuestra clase creen una instancia para invocar este único método, sin tener uso para la instancia posterior? Crear una instancia de una clase es una operación muy, muy barata en la mayoría de los lenguajes, por lo que la velocidad no es un problema. Agregar una línea adicional de código al consumidor es un costo bajo para sentar las bases de una solución mucho más fácil de mantener en el futuro. Y, por último, si desea evitar crear instancias, simplemente cree un contenedor único de su clase que permita una fácil reutilización, aunque esto exige que su clase sea apátrida. Si no es apátrida, puede crear métodos de envoltura estáticos que manejen todo, al tiempo que le brindan todos los beneficios a largo plazo. Finalmente, también podría crear una clase que oculte la creación de instancias como si fuera un singleton: MyWrapper.Instance es una propiedad que simplemente devuelve new MyClass();

Solo un Sith trata en absolutos

Por supuesto, hay excepciones a mi disgusto por los métodos estáticos. Las verdaderas clases de utilidad que no presentan ningún riesgo para la hinchazón son casos excelentes para los métodos estáticos: System.Convert como ejemplo. Si su proyecto es único y no requiere mantenimiento futuro, la architecture general no es muy importante: estática o no estática, realmente no importa, sin embargo, la velocidad de desarrollo sí lo es.

Estándares, estándares, estándares!

El uso de métodos de instancia no le impide usar también métodos estáticos, y viceversa. Mientras haya un razonamiento detrás de la diferenciación y esté estandarizado. No hay nada peor que mirar por encima de una capa de negocios con diferentes métodos de implementación.

Al decidir si hacer que una clase sea estática o no estática, debe ver qué información está tratando de representar. Esto conlleva un estilo de progtwigción más ” ascendente ” en el que te centras primero en los datos que estás representando. Es la clase en la que estás escribiendo un objeto del mundo real como una piedra o una silla? Estas cosas son físicas y tienen atributos físicos como el color y el peso, lo que indica que es posible que desee crear instancias de objetos múltiples con diferentes propiedades. Es posible que desee una silla negra Y una silla roja al mismo tiempo. Si alguna vez necesita dos configuraciones al mismo tiempo, inmediatamente sabrá que desea crear una instancia como un objeto para que cada objeto pueda ser único y existir al mismo tiempo.

En el otro extremo, las funciones estáticas tienden a prestar más a las acciones que no pertenecen a un objeto del mundo real o un objeto que puede representar fácilmente. Recuerda que los predecesores de C # son C ++ y C, donde puedes definir funciones globales que no existen en una clase. Esto presta más a la progtwigción ‘de arriba hacia abajo ‘. Los métodos estáticos se pueden usar para estos casos en los que no tiene sentido que un ‘objeto’ realice la tarea. Al forzarte a usar clases, esto hace que sea más fácil agrupar la funcionalidad relacionada, lo que te ayuda a crear un código más fácil de mantener.

La mayoría de las clases pueden representarse estáticas o no estáticas, pero cuando tenga dudas simplemente vuelva a las raíces de su OOP y trate de pensar sobre lo que está representando. ¿Es este un objeto que está realizando una acción (un automóvil que puede acelerar, ralentizar, girar) o algo más abstracto (como mostrar la salida).

¡Ponte en contacto con tu OOP interno y nunca te equivocarás!

Para C # 3.0, los métodos de extensión solo pueden existir en clases estáticas de nivel superior.

Si usa herramientas de análisis de código (por ejemplo, FxCop ), le recomendará marcar un método static si ese método no accede a los datos de la instancia. La razón es que hay una ganancia de rendimiento. MSDN: CA1822 – Marca miembros como estáticos .

Es más una guía que una regla, realmente …

Tiendo a usar clases estáticas para fábricas. Por ejemplo, esta es la clase de registro en uno de mis proyectos:

 public static class Log { private static readonly ILoggerFactory _loggerFactory = IoC.Resolve(); public static ILogger For(T instance) { return For(typeof(T)); } public static ILogger For(Type type) { return _loggerFactory.GetLoggerFor(type); } } 

Es posible que incluso haya notado que se llama IoC con un acceso estático. La mayoría de las veces, para mí, si puedes llamar a métodos estáticos en una clase, eso es todo lo que puedes hacer, así que marcó la clase como estática para mayor claridad.

Empecé a usar clases estáticas cuando deseo usar funciones, en lugar de clases, como mi unidad de reutilización. Anteriormente, yo era todo sobre el mal de las clases estáticas. Sin embargo, aprender F # me ha hecho verlos bajo una nueva luz.

¿Qué quiero decir con esto? Bueno, digamos que cuando preparo un código super DRY , termino con muchas clases de método único. Puedo simplemente colocar estos métodos en una clase estática y luego insertarlos en dependencias usando un delegado. Esto también funciona bien con mi contenedor de dependency injection (DI) de Autofac.

Por supuesto, tomar una dependencia directa de un método estático sigue siendo generalmente malo (hay algunos usos no malvados).

Utilizo las clases estáticas como un medio para definir “funcionalidad adicional” que un objeto de un tipo dado podría usar bajo un contexto específico. Por lo general, resultan ser clases de utilidad.

Aparte de eso, creo que “Usar una clase estática como unidad de organización para métodos no asociados con objetos particulares”. describir bastante bien su uso previsto.

Las clases estáticas son muy útiles y tienen un lugar, por ejemplo, bibliotecas.

El mejor ejemplo que puedo proporcionar es la clase .Net Math, una clase estática del espacio de nombres del sistema que contiene una biblioteca de funciones matemáticas.

Es como cualquier otra cosa, use la herramienta adecuada para el trabajo, y si no se puede abusar de nada.

Descartar en blanco las clases estáticas como incorrectas, no las use, o decir “solo puede haber una” o ninguna, es tan erróneo como exagerar al usarlas.

C # .Net contiene varias clases estáticas que se usan como la clase de Matemáticas.

Entonces, dada la correcta implementación, son tremendamente útiles.

Tenemos una clase TimeZone estática que contiene varias funciones de zona horaria relacionadas con el negocio, no hay necesidad de crear varias instancias de la clase tanto como la clase Math contiene un conjunto de funciones reajustadas TimeZone (métodos) globalmente accesibles en una clase estática .

Esta es otra pregunta antigua pero muy candente desde que OOP se unió. Hay muchas razones para usar (o no) una clase estática, por supuesto y la mayoría de ellas han sido cubiertas en la multitud de respuestas.

Simplemente agregaré mis 2 centavos a esto, diciendo que, hago una clase estática, cuando esta clase es algo que sería único en el sistema y que realmente no tendría sentido tener instancias de ella en el progtwig. Sin embargo, reservo este uso para grandes clases. Nunca declaro clases tan pequeñas como en el ejemplo de MSDN como “estática” y, ciertamente, no clases que van a ser miembros de otras clases.

También me gustaría señalar que los métodos estáticos y las clases estáticas son dos cosas diferentes a considerar. Las principales desventajas mencionadas en la respuesta aceptada son para métodos estáticos. Las clases estáticas ofrecen la misma flexibilidad que las clases normales (donde las propiedades y los parámetros se refieren), y todos los métodos utilizados en ellos deben ser relevantes para el propósito de la existencia de la clase.

Un buen ejemplo, en mi opinión, de un candidato para una clase estática es una clase “FileProcessing”, que contendría todos los métodos y propiedades relevantes para los diversos objetos del progtwig para realizar operaciones complejas de FileProcessing. Difícilmente tiene sentido tener más de una instancia de esta clase y ser estático lo hará disponible para todo en su progtwig.

Solo uso las clases estáticas para los métodos de ayuda, pero con la llegada de C # 3.0, preferiría usar métodos de extensión para esos.

Raramente uso métodos de clases estáticas por las mismas razones por las que raramente utilizo el “patrón de diseño” singleton.

Basado en MSDN :

  1. No puede crear la instancia para clases estáticas
  2. Si la clase declarada como estática, la variable miembro debe ser estática para esa clase
  3. Sellado [No puede ser heredado]
  4. No puede contener el constructor Instance
  5. Gestión de la memoria

Ejemplo: cálculos matemáticos (valores matemáticos) no cambia [CÁLCULO ESTÁNDAR PARA VALORES DEFINIDOS]