¿Debo usar clases estáticas para métodos que realizarán tareas comunes y se llamarían a través de mi aplicación?

8

He pasado las últimas horas leyendo sobre el uso de las staticclases y tratando de averiguar si debería usarlas o no, pero aún no he llegado a ninguna conclusión. Parece que el argumento podría ir en cualquier dirección. En mi aplicación, he creado lo que llamo "clases auxiliares", que contiene métodos que realizarán tareas muy comunes para mí y se llamarían a través de mi aplicación ( ASP.Net MVCusando la aplicación web C#) y la simple pregunta es, ¿deberían ser realmente estáticos o no? ?

Aquí hay un ejemplo de uno de mis ayudantes.

public static class ActiveDirectoryHelper
{
    public static PrincipalContext GetPrincipalContext(string ouName)
    {
        var fullOUName = string.Concat("OU=", ouName,",DC=");

        return new PrincipalContext(ContextType.Domain, "", fullOUName, ConfigurationManager.AppSettings["ServiceAccountUser"], ConfigurationManager.AppSettings["ServiceAccountPassword"]);
    }

    public static PrincipalSearcher GetAllUsersInOU(string ouName)
    {
        var principalContext = GetPrincipalContext(ouName);
        var userPrincipal = new UserPrincipal(principalContext);
        return new PrincipalSearcher(userPrincipal);
    }

    public static UserPrincipal GetUserPrincipal(string userName, string ouName)
    {
        var principalContext = GetPrincipalContext(ouName);
        return UserPrincipal.FindByIdentity(principalContext, userName);
    }
}
Matthew Verstraete
fuente
No hay mandato para evitar clases estáticas. Úsalos cuando sea útil hacerlo. Hay buenas razones por las que los diseñadores de idiomas los incluyeron.
Robert Harvey
55
¿Por qué no incluiste estos métodos como métodos estáticos en sus clases asociadas, en lugar de ponerlos a todos en una clase auxiliar? Por ejemplo, el primer método podría ser un método estático en la PrincipalContextclase, y será llamado como: PrincipalContext.Get(ouName). Es esencialmente un método de fábrica.
Robert Harvey
@RobertHarvey No creo que te esté siguiendo. Esta clase está en mi BLL y se llama desde muchas otras clases (controladores) en la WebUI, así como en una aplicación de consola C # que realiza tareas de mantenimiento nocturno y para evitar tener que volver a codificarla todo el tiempo que acabo de escribirla en una clase auxiliar.
Matthew Verstraete
55
El desarrollo de software es siempre una serie de compensaciones. La técnica que elija utilizar depende del conjunto de compensaciones que desee aplicar.
Robert Harvey
44
@RobertHarvey: PrincipalContext y UserPrincipal son clases de biblioteca,
kevin cline

Respuestas:

3

Creo que las clases estáticas son buenas en muchos casos. Podría simplemente decir "úselas cuando sea útil", pero eso no es muy útil.

Mi regla general es (como siempre): ¿estoy ocultando alguna dependencia? Si crees que una "clase auxiliar" es útil (aunque ten cuidado con la baja cohesión), entonces, por supuesto, adelante. Sin embargo, solo asegúrese de que sus métodos no accedan al estado global. Los métodos estáticos puros son encantadores. Los métodos estáticos que dependen de algunos globales o que abren conexiones DB o leen desde el disco / algún archivo de configuración son bombas de tiempo.

Hacen que probar la aplicación sea realmente difícil (la única forma de hacerlo será ejecutar manualmente todo el sistema, o con pruebas frágiles automáticas de todo el sistema, no obtendrá granularidad). También hacen que sea imposible intercambiar implementaciones.

¡Solo recuerda el principio de inversión de dependencia y el principio abierto / cerrado! Asegúrate de que tus clases sean conectables. Asegúrese de que no saquen cosas de la nada. Si haces eso, ¡adelante y crea tantos métodos estáticos como quieras!

sara
fuente
2

Parece que está ocultando una dependencia externa a Active Directory usando esta clase estática. Un problema aquí es que si está intentando probar unitariamente la clase que llama a estos métodos, no puede falsificar llamadas estáticas. Entonces inhibe de inmediato la capacidad de prueba de su código. Refactorizaría esto a una interfaz, algo así como IProvideActiveDirectoryInformation y una clase concreta, ActiveDirectoryInformationProvider. Luego pase la interfaz en el constructor de su controlador. Esto le permitirá conectar la clase de concreto con un contenedor DI. También le permitirá falsificar el ActiveDirectoryInformationProvider y devolver lo que desee para los métodos de interfaz.

También me gustaría no pasar cosas como el objeto PrincipalSearcher en la interfaz. Si su método es GetAllUsersInOU (), esperaría una lista de usuarios o nombres de usuario.

Fran
fuente
No estoy seguro de lo que quiere decir con "ocultar una dependencia externa de Active Directory". Realizo lecturas desde AD y esta clase se creó para reducir la codificación necesaria para hacer conexiones y obtener datos básicos.
Matthew Verstraete
eso es lo que quiero decir. Vea la respuesta de Kai para una explicación más completa. Pero lo que debe hacer es no hacer que su código dependa de todas las dependencias del código de su llamada.
Fran
1

Una clase debe ser estática si solo existe como un concepto abstracto en su aplicación.

Por ejemplo, supongamos que está creando un clon de Twitter. Puede tener 2 tipos de tweets, tweets de usuario y anuncios. Ambos comparten un comportamiento común pero son diferentes. Por lo tanto, desea utilizar el polimorfismo y una fábrica para crear uno u otro.

Esas 2 clases de tweets deben ser clases concretas, ya que son entidades reales. Su dominio está definido por estas clases.

La fábrica debe ser estática porque solo existe en un nivel abstracto para hacer que su aplicación esté mejor diseñada y para ayudarlo a reutilizar el código que creará un tipo de tweet. Su dominio no está definido en ningún nivel por esta fábrica.

Por lo tanto, si no cree que una clase deba ser instanciada alguna vez, pero no necesita extenderse para usarse, probablemente sea una buena señal de que debería ser estática.

Steve Chamaillard
fuente
Esto realmente dependería del tipo de fábrica. Un simple static A BuildA() { return new A(); }seguro, está bien. pero si necesita algo más complejo, como cuando A tiene dependencias que necesitan inyectarse o cuando diferentes partes de su sistema necesitan diferentes instancias de fábrica (patrón de fábrica abstracto), entonces un método estático no lo cortará.
Sara
Gracias por tu comentario. No parece que la fábrica de la que estás hablando sea tan abstracta al final, parece que es un concepto concreto que necesita ser instanciado (especialmente porque dijiste que necesitabas múltiples fábricas diferentes). Por otra parte, nada está escrito en piedra de todos modos y solo se pueden dar consejos sobre este tema.
Steve Chamaillard
1
Existen muchas entidades que son "Fabricación Pura", que de ninguna manera o forma se traducen al dominio, por ejemplo, UserDao. Sin embargo, esto no es una indicación de si debe ser estático o no. Debe ser estático si las unidades de trabajo que realiza, no dependen unas de otras, y debe ser extensible, por ejemplo, clase de matemáticas.
Chris Wohlert
@ChrisWohlert comentario muy interesante (aprobado), pero ¿no depende únicamente del contexto? Siento que una aplicación sobre matemáticas querría que una clase de Matemáticas sea una de las clases principales y que se pueda instanciar. ¿El usuario es algún tipo de repositorio entre el usuario y la capa de base de datos? Si es así, ¿por qué querrías instanciarlo? Todavía podría inyectarlo aunque nunca crearía un objeto para esto, ya que no "existe", ¿qué piensa?
Steve Chamaillard
1
@SteveChamaillard Tiene la suposición de que tiene sentido crear instancias solo de objetos "reales". Me recuerda estas analogías de OOP 101 donde tienes una clase abstracta "Fruit" y una "Apple" heredada, donde los objetos OOP representan objetos del mundo real. Pero no hay necesidad de limitarse así. OOP es una herramienta, por lo que las personas usan objetos para "fabricaciones puras", incluso eso les hace la vida más fácil y no veo nada de malo en eso ...
qbd
1

Una de las cosas sugeridas en la Programación Orientada a Objetos es Mala (el título es para llamar su atención, y el contenido es disputado pero entretenido) es que *Handler, *Managery las *Doerclases en general son un olor a código que indica que alguien está tratando de forzar la orientación del objeto a un problema que es más adecuado para una implementación de procedimiento.

En C # puede usar clases estáticas como espacios de nombres de módulos para procedimientos y, preferiblemente, nombrarlos como tales. Creo que así es como hacerlo, pero no en su caso particular.

Las aplicaciones de su implementación particular tendrán dependencias de comportamiento del estado global (digamos los permisos de un usuario en particular), y como tal deberían ser una dependencia inyectada para que el código que usa esto pueda probarse de forma aislada.

Robert Jørgensgaard Engdahl
fuente
0

Puede que me falte algo, pero en mi opinión la respuesta se reduce a los métodos y las variables miembro.

Si todo esto es estático, la clase en sí misma puede (y debería) hacerse estática. Si no, entonces no es una clase estática.

Nota: no hay nada que obligue a la clase a ser estática, incluso si los métodos y las variables son estáticos.

Robbie Dee
fuente
La misma clase que hace las mismas cosas puede diseñarse para ser tanto estática como no estática. Siempre hay que elegir un diseño.
Sara
Puede haber una opción de diseño, pero la implementación es algo arbitraria. Nada lo obliga a etiquetar el método o la clase como estática, incluso con la falta de una variable de instancia, aunque algunas herramientas como ReSharper se dan cuenta de esto ...
Robbie Dee
Pero, ¿cuándo debería hacer que todos los métodos / miembros sean estáticos o no? Esa es la pregunta. Cuándo usar estática y cuándo no.
Matthew Verstraete
Si ninguna de las variables o métodos miembros depende de una instancia de la clase, usted tiene una clase estática de buena fe. Por su naturaleza, estos tienden a ser cosas como clases de ayuda o servicios públicos y similares.
Robbie Dee
0

Considere el lenguaje de programación que está utilizando (C #) como un conjunto de herramientas.

No hay un libro de reglas, no "debería" o "no debería".

Mire el trabajo que está haciendo y elija la mejor herramienta para el trabajo.

Si necesita una colección de métodos disponibles en todo el mundo, lo mismo para todos los hilos, entonces las clases estáticas son una buena herramienta. Si desea almacenar datos dentro de la clase (diferentes para cada hilo), probablemente no lo sean.


fuente
0

No hay nada malo en tu clase de ayudante. Tengo que confesar que uso este tipo de Utils , Helpers o Holders para hacer accesibles ciertos recursos / lógica desde diferentes lugares.

Sin embargo, un arquitecto de mi compañía me dice una y otra vez que estas clases a menudo recopilan código que no sé dónde ubicar. Tampoco le gusta porque podría traer componentes de capas donde las capas superiores / inferiores no deberían tener acceso y realizan tareas fuera de sus responsabilidades. También trae algunos problemas en el momento de la prueba.

No me importa Los uso y los uso tan bien como creo que debería usarse. Y funciona bien. Entonces no te preocupes.

Es cierto que en el momento de la prueba de la unidad tendrá dificultades para burlarse de ella. Pero tomará un poco más de tiempo hacerlo. Hay libs que pasan por este problema.

Otro enfoque podría evitarle este tipo de deficiencias (en las pruebas). Por ejemplo, patrón Singleton. Inyectar la instancia como dependencia de componentes y convertir los métodos en métodos de instancia.

De todos modos, hasta ahora veo, sus soluciones me parecen bien.

Laiv
fuente