¿No utiliza "estático" en C #?

109

Envié una solicitud que escribí a otros arquitectos para la revisión del código. Uno de ellos casi inmediatamente me respondió y dijo "No use" estático ". No puede escribir pruebas automatizadas con clases y métodos estáticos." Debe evitarse "estático".

Revisé y 1/4 de mis clases están marcadas como "estáticas". Utilizo static cuando no voy a crear una instancia de una clase porque la clase es una clase global única utilizada en todo el código.

Luego mencionó algo relacionado con la burla, las técnicas IOC / DI que no se pueden usar con código estático. Él dice que es desafortunado cuando las bibliotecas de terceros son estáticas debido a su imposibilidad de prueba.

¿Es este otro arquitecto correcto?

actualización: aquí hay un ejemplo:

APIManager: esta clase mantiene diccionarios de API de terceros a los que llamo junto con el próximo tiempo permitido. Aplica los límites de uso de API que muchos terceros tienen en sus términos de servicio. Lo uso en cualquier lugar donde llamo a un servicio de terceros llamando a Thread.Sleep (APIManager.GetWait ("ProviderXYZ")); antes de hacer la llamada. Todo aquí es seguro para subprocesos y funciona muy bien con el TPL en C #.

Infin8Loop
fuente
37
staticestá bien; static los campos deben ser tratados con mucho cuidado
Marc Gravell
2
¿Por qué escribiría pruebas para bibliotecas de terceros? ¿No sueles probar tu propio código suponiendo que los creadores de la biblioteca de terceros hayan realizado sus pruebas?
No
3
Esa objeción particular es demasiado general para mí. En la mayoría de los casos, no usarías la clase estática, te burlarías de los argumentos. Campo estático donde era una clase agregada que necesitaba burlarse, entonces sí.
8
Claramente, sus colegas tienen una afección grave: una OOP eritematosa sistémica aguda. ¡Necesitan un tratamiento lo antes posible!
SK-logic
66
Hay una sección de respuestas para proporcionar respuestas, no entiendo por qué las personas comentan en un intento de dar una respuesta / sugerencia a alguien ... Derrota el propósito de StackExchange, seguramente un comentario sería solicitar más información.
peteski

Respuestas:

121

Depende de si las clases estáticas mantienen el estado o no. Personalmente, no tengo ningún problema con las funciones sin estado agrupadas en una clase estática.

Larsenal
fuente
111
Correcto. Las funciones estáticas que no tienen efectos secundarios son las funciones más comprobables de todas.
Robert Harvey
99
+1 a eso, pero con una cláusula de seguridad: casi todos los algoritmos abstractos no tienen estado, pero eso no significa que debas implementarlo como una clase o método estático sin estado. Implementarlo de esta manera hace que todo el código que lo usa apenas esté vinculado a él. Esto significa, por ejemplo, que si implementa un algoritmo de ordenación como método estático y luego lo utiliza durante el proyecto, no puede reemplazar temporalmente la ordenación por otro algoritmo, es decir, con fines de prueba y para limitar el área del problema. Este es un gran obstáculo en muchos casos. Aparte de eso, la estática está totalmente bien si se usa razonablemente.
11
En resumen: son las funciones más comprobables, pero no necesariamente hacen que el otro código sea más comprobable. Esto es lo que el arquitecto quiso decir probablemente.
44
@ tereško: el lenguaje C # requiere métodos estáticos para formar parte de una clase estática, si no desea tener que crear una instancia de la clase para llamar al método. Quizás te refieres a "instancia" y no a "clase".
Robert Harvey
8
@quetzalcoatl: es perfectamente legal pasar un delegado (es decir, un algoritmo diferente) a un método estático; Los métodos de extensión en Linq son todos métodos estáticos. Ejemplo: msdn.microsoft.com/en-us/library/…
Robert Harvey
93

Él es demasiado general al respecto. Tiene razón, dificulta las pruebas. Sin embargo, las staticclases y los métodos tienen su lugar y realmente depende del contexto. Sin ejemplos de código, realmente no se puede saber.

Utilizo static cuando no voy a crear una instancia de una clase porque la clase es una clase global única utilizada en todo el código.

Esto puede ser un fuerte olor a código. ¿Para qué estás usando las clases? Para mantener los datos? Para acceder a una base de datos? Entonces él está en lo correcto. Debería buscar la inyección de dependencia en ese caso, ya que tal clase estática es efectivamente un singleton implícito.

Si los está utilizando para métodos de extensión o ayudantes que no cambian el estado y solo operan con los parámetros que proporciona, generalmente están bien.

Femaref
fuente
3
+1 por mencionar que la declaración era general y mencionar métodos de extensión, que también se pueden probar y las dependencias aún se pueden burlar hasta donde yo sé.
No
44
Sí, estático como instancia de clase única como un singleton implícito, eso se volverá desordenado ...
"¿Para acceder a una base de datos?" Por qué no ? si el adaptador de tabla no es estático, entonces crea un conjunto de datos estático de clase @ fuertemente tipado, no tiene nada de malo ... a menos que demuestre su punto con referencia o ejemplo
Matemáticas
27

Revisé y 1/4 de mis clases están marcadas como "estáticas". Utilizo static cuando no voy a crear una instancia de una clase porque la clase es una clase global única utilizada en todo el código.

Lo mejor que puedes hacer es probar y hacer una prueba unitaria de tu código. Intente diseñar pruebas que sean repetibles, independientes, simples y pruebe solo un método a la vez. Intente ejecutar sus pruebas en un orden aleatorio diferente. ¿Se puede obtener una construcción "verde" estable?

En caso afirmativo, ese es un punto válido para defender su código. Sin embargo, si tiene dificultades, entonces tal vez debería optar por métodos basados ​​en instancias.

oleksii
fuente
77
Este es el punto que también me llamó la atención. Algunas clases de estilo 'auxiliar' estáticas y sin estado están bien, pero si tiene un 25% de todas sus clases como estáticas, es poco probable que sus esfuerzos se limiten a ese caso.
Matthew Scharley
2
@MatthewScharley: probablemente recibió 4 clases, y una de ellas es estática :)
Alexus
1
Tenga en cuenta que si usa tales stibcs (como singletons), crear más instancias más tarde podría ser un trabajo difícil. Por ejemplo, al crear una aplicación que maneja un documento, más tarde tendrá problemas cuando desee administrar varios documentos.
Michel Keijzers
11

Las respuestas ya publicadas cubren muchos puntos realmente buenos, pero hay uno que parece faltar:

Los campos estáticos nunca son basura recolectada.

Esto es realmente importante si tiene una aplicación con muchas restricciones de memoria, y este patrón puede ser muy común cuando las personas intentan implementar un caché.

Las funciones estáticas no son tan malas, pero todos los demás ya lo han cubierto con suficiente detalle.

Riwalk
fuente
10

Una de las ventajas que obtiene de IoC / DI es que la mayoría de las interacciones entre clases se negocian entre interfaces. Esto facilita la prueba de la unidad porque las interfaces se pueden burlar automática o semiautomáticamente y, por lo tanto, cada una de las partes se puede probar para entradas y salidas. Además, más allá de la capacidad de prueba, poner interfaces entre todo le permite tener el código más modular posible: puede reemplazar fácilmente una implementación sin preocuparse tanto de que esté arruinando dependencias.

Debido a que C # no tiene metaclases, una clase no puede implementar una interfaz usando características estáticas, por lo que las características estáticas de las clases terminan arruinando cualquier esfuerzo para implementar un modelo de objeto IoC / DI puro. Es decir, no puedes crear un simulacro para probarlos, y tienes que crear dependencias reales.

Si su empresa / proyecto invierte mucho en hacer IoC, esto, por supuesto, es una preocupación razonable, y el dolor que atraviesa es por el beneficio de todos. Sin embargo, desde un punto de vista arquitectónico, personalmente no creo que se deba seguir ningún modelo hasta la tumba. Hay algunas cosas que tienen sentido implementar usando métodos estáticos, por ejemplo, la estrategia de diseño singleton. Yo mismo estoy menos inclinado a las clases estáticas porque creo que tienden a perder las ventajas de OO, pero a veces una clase de biblioteca es probablemente una expresión más natural de algo que un motor.


El comentarista me recuerda los métodos de extensión, que por supuesto tienen que estar en clases estáticas en C #. Eso es legítimo, y es un ejemplo de cómo IoC puro no funciona muy bien en C #, al menos si está tratando de aprovechar la amplitud del lenguaje.

jwrush
fuente
1
Si una clase se hace estática por los motivos correctos y se implementa correctamente, como por ejemplo los métodos de extensión, todavía se pueden probar mucho, ya que no tendrían dependencias externas y son independientes y, por lo tanto, no deberían ser objeto de burla. ¿Debería la necesidad de una interfaz no ser impulsada por el requisito de diseño para completar mejor un requisito comercial no por el simple hecho de mantener un proyecto IoC / DI puro?
No
1
Usted y yo estamos de acuerdo en el punto general de que debe elegir la herramienta adecuada para el trabajo correcto y no dejarse llevar por la filosofía. Sin embargo, si existe una cultura bien establecida en su proyecto de IoC / DI puro, dolerá tanto como convertir una solución tradicional de arriba hacia abajo a IoC / DI. La ingeniería necesita considerar los costos de transición. Por cierto, no creo que los métodos de extensión te lleven allí. Creo que una mejor solución para el comportamiento de IoCish con clases estáticas sería tener varias clases elegidas en tiempo de compilación con directivas de preprocesador, estilo C
jwrush
1
Er. Soy tonto. Se refería a una clase estática para los métodos de extensión HOLDING, que, por supuesto, es cómo debe hacerlos. Sí, por supuesto, quieres una clase estática para ese propósito. Eso se me pasó por la cabeza: y esto demuestra que C # no estaba destinado a IoC. :)
jwrush
Sí, tiene razón, si existe una cultura existente en un proyecto existente, sería más perjudicial que ayudar a cambiar la forma en que se hacen las cosas.
No
5

Las clases estáticas a veces se usan mal y deben ser:

  • un singleton (donde la clase no estática tiene un miembro estático y una variable de instancia pública estática para recuperarla / crearla solo una vez).
  • un método en otra clase (donde el estado importa). Si tiene un miembro que no utiliza datos de esa clase, probablemente no debería ser parte de esa clase.

También podría ser una función llamada 'utilidad' y parte de una clase de utilidad. Las clases de utilidad son clases que contienen solo métodos estáticos y sirven como funciones auxiliares sin ningún contexto.

Michel Keijzers
fuente
@topomorto Debido a que la clase no debería ser instanciada por su constructor que resulta en múltiples objetos / instancias, sino por un método especial (normalmente instancia ()) <que devuelve siempre la misma instancia, instanciada después de la primera llamada a instancia ().
Michel Keijzers
@topomorto Acabo de comprobar y tienes toda la razón, solo algunos miembros son estáticos (la variable de instancia y la función de instancia). Cambiaré mi respuesta en consecuencia; gracias por mencionar
Michel Keijzers
4

Los métodos estáticos están bien para usar y tienen un lugar legítimo en la programación. Parece que su arquitecto tiene un marco de prueba que no es totalmente compatible con los métodos estáticos. Si su código es parte de un proyecto más grande, entonces es importante cumplir con las pautas de los arquitectos. Sin embargo, no permita que este proyecto le impida utilizar métodos estáticos cuando sea apropiado.

k rey
fuente
1

He estado usando propiedades estáticas para cosas que son comunes a todas las instancias de una clase. Y he estado usando métodos estáticos para obtener grupos de objetos de clase. De ninguna manera soy un experto, pero esto me ha funcionado hasta ahora.

Ejemplo de PHP:

class vendorData {
  private static $data_table = 'vendor_data'; // static property
  private $id; // instance property
  private $name; // instance property

  public function __construct($vendor_id) {
    if(!self::validId($vendor_id) ) { // static method
      return false; // id doesn't exist
    }
    $this->id = $vendor_id; // id has been validated
    $this->getProperties(); // object method
  }

  private static function validId($vendor_id) {
    // send db query to find if the id exists
    // return true/false;
  }

  private function getProperties() { // object method
    $sql = "SELECT * FROM `{self::$data_table}` // using static property
        WHERE `id` = {$this->id}"; // using object instance property
    // get resultset
    foreach($result as $property => $value) {
      $this->$property = $value; // object instance properties all set
    }
  }

  // and here
  public static function getBy($property,$value) { // static method to return object array
    $sql = "SELECT `id` FROM `{self::$data_table}` // using static property
      WHERE `$property` = '$value'";
    // send query, get $ids array
    $obj_array = array();
    foreach($ids as $id) {
      // create array of current class objects using special static keyword
      // meaning of static here is different than in property/method declarations
      $obj_array[$id] = new static($id);
    }
    return $obj_array;
  }
}
Buttle Butkus
fuente
1

Diré que los principios que tienen están bien, pero la declaración (no use estadísticas) puede estar equivocada. ¿Cuánto cuesta su código de cobertura? Si el número es alto y se siente cómodo con la prueba unitaria de su aplicación, entonces está bien. Si no, entonces sugeriría revisar el código. Puede encontrar que las clases estáticas son la razón o no, dependerá de muchas cosas.


fuente
-3

Las clases con métodos estáticos abusan de los principios de OOP. Ya no es una OOP, es COP - programación orientada a clases.

Raramente tienen una clara "personalidad" (uso mi metáfora humana favorita aquí), o identidad. Entonces no saben quiénes son. Este punto solo es suficiente para deshacerse de este concepto en OOP, pero hay más de ellos.

El siguiente es una consecuencia del primer punto. Como esas clases no saben quiénes son, tienden a ser de grandes a enormes.

El tercero hace que su código sea absolutamente no mantenible. El uso de métodos estáticos introduce dependencias ocultas . Aparecen por todas partes, y nunca se sabe lo que está sucediendo en su clase. No puede estar seguro de eso solo mirando la firma del constructor.

Lentamente, pero inevitablemente, su código se vuelve cada vez menos cohesivo, ya que las dependencias ocultas están mal controladas. Parecen invisibles ¡Y es tan fácil agregar otro! No tiene que modificar la firma de ningún método. Todo lo que tienes que hacer es llamar a un método estático. Y qué código feo sigue ...

Ok, probablemente ya lo has adivinado. El acoplamiento apretado es a menudo un acompañante de baja cohesión. Si hay muchos clientes que usan alguna clase, entonces el acoplamiento se está haciendo más estricto. Y hay una gran seducción al usar una clase o método ya escrito que requiere solo una pequeña solución. Solo un método flag-parameter.

¿Qué usar en lugar de métodos estáticos? Bueno, mi sugerencia es OOP. ¿Por qué no intentarlo?

Zapadlo
fuente