He pasado las últimas horas leyendo sobre el uso de las static
clases 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 MVC
usando 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);
}
}
c#
object-oriented-design
asp.net-mvc
Matthew Verstraete
fuente
fuente
PrincipalContext
clase, y será llamado como:PrincipalContext.Get(ouName)
. Es esencialmente un método de fábrica.Respuestas:
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!
fuente
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.
fuente
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.
fuente
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á.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
,*Manager
y las*Doer
clases 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.
fuente
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.
fuente
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
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.
fuente