¿Por qué y cuándo debo hacer una clase 'estática'? ¿Cuál es el propósito de la palabra clave 'estática' en las clases?

47

La staticpalabra clave en un miembro en muchos idiomas significa que no debe crear una instancia de esa clase para poder tener acceso a ese miembro. Sin embargo, no veo ninguna justificación para hacer una clase completa static. ¿Por qué y cuándo debo hacer una clase static?

¿Qué beneficios obtengo al hacer una clase static? Quiero decir, después de declarar una clase estática, uno aún debe declarar a todos los miembros a los que quiere tener acceso sin instanciación, como estáticos también.

Esto significa que, por ejemplo, la Mathclase podría declararse normal (no estática), sin afectar la forma en que los desarrolladores codifican. En otras palabras, hacer que una clase sea estática o normal es algo transparente para los desarrolladores.

Saeed Neamati
fuente
Si está codificando en el estilo Func Prog a la Rich Hickey, esto puede ser útil.
Trabajo
1
En mi opinión, las clases estáticas son simplemente una muleta a través de la cual C # intenta ocultar un defecto de diseño masivo en el lenguaje. ¿Por qué estructurar un lenguaje en torno a esta ideología absurda de todo tiene que ser una clase, solo para luego introducir una sintaxis adicional para que pueda hacer trampa y evitar esta restricción innecesaria? Si C # acabara de permitir funciones gratuitas desde el principio, no habría necesidad de clases estáticas.
antred

Respuestas:

32

Hace obvio para los usuarios cómo se usa la clase. Por ejemplo, no tendría sentido escribir el siguiente código:

Math m = new Math();

C # no tiene que prohibir esto, pero dado que no sirve para nada, también podría decirle al usuario eso. Ciertas personas (incluyéndome a mí) se adhieren a la filosofía de que los lenguajes de programación (y las API ...) deberían ser lo más restrictivos posible para que sean difíciles de usar incorrectamente: las únicas operaciones permitidas son aquellas que son significativas y (con suerte) correctas.

Konrad Rudolph
fuente
3
No estoy de acuerdo con esa filosofía. El problema que tengo es que necesita un cambio. Entonces, aunque puede tener sentido restringirlo antes, esa restricción dificulta nuestro desarrollo para futuras necesidades. Y la biblioteca heredada que estamos obligados a usar para interactuar con el sistema antiguo (el que usted escribió y selló y estátizó todas las clases) no nos proporciona ninguna forma de extender o modificar el código que escribió. El hecho de que no tengas ninguna razón para crear una instancia de tu clase no significa que no la necesite en el futuro. Si bien la estática de una clase de utilidad tiene sentido, considere el futuro también.
SoylentGray
19
@Chad Entonces la biblioteca está mal diseñada. Ampliar las clases que no fueron diseñadas para la extensión en última instancia no funciona, así que mejor hacer la clase sealeden primer lugar. Reconozco que no todas las personas están de acuerdo con este sentimiento, pero los comentarios no son un buen lugar para discutirlo. Pero en el caso de staticeste problema ni siquiera se plantea: la creación de instancias nuncaSystem.Math tendrá sentido.
Konrad Rudolph el
1
@Konard, si declara a todos los miembros de la Mathclase como estáticos sin declarar la Mathclase como estática, aún puede usarla, sin necesidad de instanciación.
Saeed Neamati
11
@Saeed: esto es cierto, pero también puede crear una instancia de la clase, que no sirve para nada. ¿Qué hago con una instancia de la clase de matemáticas? Para mostrar explícitamente la intención de la clase (no se necesita ni se desea instanciación), se marca static.
Corbin Marzo
3
@Saeed Cambiemos esto: le propongo que lea mi respuesta nuevamente ya que parece haberla entendido mal: sus comentarios no están relacionados con mi respuesta. Nunca dije que necesitaras escribir new Math().
Konrad Rudolph el
24

StackOverflow tiene una gran discusión sobre este tema . Para facilitar la consulta, lo copiaré y pegaré aquí, en nombre de su autor, Mark S. Rasmussen :

Escribí mis pensamientos sobre las clases estáticas en un hilo anterior :

Solía ​​amar las clases de utilidad llenas de métodos estáticos. Hicieron una gran consolidación de los métodos auxiliares que de otro modo estarían por ahí causando redundancia y mantenimiento infierno. Son muy fáciles de usar, sin creación de instancias, sin eliminación, solo disparar y olvidar. Supongo que este fue mi primer intento involuntario de crear una arquitectura orientada a servicios: muchos servicios sin estado que solo hicieron su trabajo y nada más. Sin embargo, a medida que el sistema crezca, vendrán dragones.

Polimorfismo

Digamos que tenemos el método UtilityClass.SomeMethod que felizmente suena. De repente, necesitamos cambiar ligeramente la funcionalidad. La mayor parte de la funcionalidad es la misma, pero debemos cambiar algunas partes. 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 dentro de ella, 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 pasarlos por su interfaz. Esto nos hace incapaces de usar clases estáticas como parte de un patrón de estrategia. Podríamos solucionar algunos problemas pasando delegados 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 código de prueba. Una vez más, podemos envolverlos, pero requerirá que cambiemos grandes partes de nuestro código solo para poder aceptar envoltorios en lugar de los objetos reales.

Fomenta manchas

Como los métodos estáticos se usan generalmente como métodos de utilidad y los métodos de utilidad generalmente tendrán diferentes propósitos, terminaremos rápidamente con una gran clase llena de funcionalidades no coherentes; idealmente, cada clase debería 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 de fluencia

Para empezar, ese pequeño método estático lindo e inocente podría tomar un solo parámetro. A medida que la funcionalidad crece, se agregan un par de parámetros nuevos. Pronto se agregan parámetros adicionales 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 tres primeros son realmente necesarios, los parámetros 4-7 son opcionales. Pero si se especifica el parámetro 6, también se deben completar 7-9 ... Si hubiéramos creado una clase con el único propósito de hacer lo que hizo este método estático, podríamos resolver esto tomando 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. También,

Exigir a los consumidores que creen una instancia de clases sin motivo.

Uno de los argumentos más comunes es, ¿por qué exigir que los consumidores de nuestra clase creen una instancia para invocar este método único, 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 idiomas, por lo que la velocidad no es un problema. Agregar una línea de código adicional 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 la creación de instancias, simplemente cree un contenedor singleton de su clase que permita una reutilización fácil, aunque esto exige que su clase no tenga estado. Si no es apátrida, aún puede crear métodos de envoltura estática que manejen todo, al tiempo que le brindan todos los beneficios a largo plazo. Finalmente,

Solo un Sith trata en términos 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 de hinchazón son casos excelentes para métodos estáticos: System.Convert como ejemplo. Si su proyecto es único y no requiere requisitos de mantenimiento futuro, la arquitectura general realmente 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 una capa de negocios en expansión con diferentes métodos de implementación.

Almiar
fuente
12
Hmmm, no sé si copiaría y pegaría una respuesta completa aquí. Tal vez el enlace y la paráfrasis, incluya un punto de vista alternativo ya que usted menciona una "discusión", ¿comparte su propia experiencia?
Corbin marzo
2
"Solo un Sith trata en términos absolutos" - No había visto que se usara así antes ... pero es PERFECTO. Me hizo jajaja.
Brook
44
@ Corbin: Mark tuvo una gran respuesta. Le di crédito y copié / pegué para facilitar la referencia. Mis propios puntos de vista sobre este asunto coinciden con los de Mark. No veo el punto de su comentario, aparte de comenzar el debate.
Rick
1
@Rick: La respuesta copiada es bastante larga, y parafrasearla definitivamente ayudaría. Solo una oración como "No es solo que no sean realmente útiles, sino que incluso pueden dañar, como lo muestra esta publicación SO:" me permitiría saltarlo rápidamente ya que veo que no es la información que estaba buscando.
blubb
@Simon: LOL I 1 + 'editó tu publicación. En un intento de dejar de discutir sobre algo tan estúpido, simplemente estaré de acuerdo. :) Espero que el póster original encuentre útil mi respuesta / copiar y pegar.
Rick
16

Me sorprende que nadie más haya mencionado que las staticclases permiten métodos de extensión : extender de forma segura un tipo existente (incluida la adición de definiciones de métodos a las interfaces ) que no es de su propiedad. Por ejemplo, lo que en Scala es

trait MyFoo {
  def foo: Int
  def plusFoo(a: Int) = foo + a
}

puede expresarse en C # como

public interface IMyFoo {
  int Foo();
}

public static class MyFooExtensions {
  public static int PlusFoo(this IMyFoo f, int a) {
    return f.Foo() + a;
  }
}
Frank Shearar
fuente
encontraste aguja en el pajar. +1
Saeed Neamati
3

Para mí, una clase estática (en C #) es como llamar a una función.

Por ejemplo

public static string DoSomething(string DoSomethingWithThisString){}

Paso una secuencia y recupero una secuencia. Todo está contenido en ese método. Sin acceso a la variable miembro, etc.

Honestamente, principalmente su uso para mí ha sido disminuir las líneas de código:

Por qué:

MyClass class = new MyClass();
String s = class.DoSomething("test");

Cuando puedo hacer esto:

String s = MyClass.DoSomething("test");

Entonces, usaría clases estáticas en esos casos, cuando quisiera hacer algo sin la necesidad de una clase y significaría menos escribir.

Los puntos de Mark S. son válidos, pero para mí, si tengo algunos métodos de utilidad, es más fácil fingir que estoy llamando a una función para hacer referencia a ellos como un revestimiento.

Eso puede ser simplista, pero así es principalmente como lo he usado static.

Jon Raynor
fuente
1
nuevo MyClass (). DoSomething ("prueba") sigue siendo válido. Lo uso mucho para Test Data Builders.
JoanComasFdz