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 otra manera se encontrarían causando redundancia y un infierno de mantenimiento. Son muy fáciles de usar, no se crean instancias, no se eliminan, solo dispara y olvida. 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 crece, 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 .
Prueba
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. Nuevamente, podemos envolverlos, pero requerirá que cambiemos grandes partes de nuestro código solo para poder aceptar envoltorios en lugar de los objetos reales.
Fomenta los blobs
Como los métodos estáticos generalmente se usan 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 funcionalidad no coherente; 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 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 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. Además, si un método ha crecido a esta cantidad de complejidad,
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 que usar la instancia después? 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 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 la creación de instancias, simplemente cree un contenedor singleton de su clase que permita una fácil reutilización, 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 los métodos estáticos: System.Convert como ejemplo. Si su proyecto es único, sin requisitos para el 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.
this
, debe administrar el estado global, etc. si te gusta la programación de procedimientos, haz esto. Pero aprecie que luego pierde muchos de los beneficios estructurales de OO.Prefiero la forma estática. Como la clase no representa un objeto, no tiene sentido hacer una instancia de él.
Las clases que solo existen para sus métodos deben dejarse estáticas.
fuente
Si no hay ninguna razón para crear una instancia de la clase para ejecutar la función, utilice la implementación estática. ¿Por qué hacer que los consumidores de esta clase creen una instancia cuando no se necesita?
fuente
Si no necesita guardar el estado del objeto, no hay necesidad de instanciarlo en primer lugar. Iría con el método estático único al que le pasas los parámetros.
También advertiría contra una clase gigante de Utils que tiene docenas de métodos estáticos no relacionados. Esto puede ser desorganizado y difícil de manejar a toda prisa. Es mejor tener muchas clases, cada una con pocos métodos relacionados.
fuente
Yo diría que el formato del método estático sería la mejor opción. Y también haría que la clase sea estática, de esa manera no tendría que preocuparse por crear accidentalmente una instancia de la clase.
fuente
Realmente no sé cuál es la situación aquí, pero consideraría ponerlo como un método en una de las clases a las que pertenecen arg1, arg2 o arg3. Si puede decir semánticamente que una de esas clases sería propietaria del método.
fuente
Sugeriría que es difícil de responder en función de la información proporcionada.
Mi instinto es que si solo vas a tener un método y vas a tirar la clase de inmediato, entonces conviértela en una clase estática que tome todos los parámetros.
Por supuesto, es difícil decir exactamente por qué necesita crear una sola clase solo para este método. ¿Es la típica situación de "clase de utilidades" como la mayoría asume? ¿O está implementando algún tipo de clase de regla, de la cual podría haber más en el futuro?
Por ejemplo, haga que esa clase sea conectable. Luego, desearía crear una interfaz para su único método, y luego desearía que todos los parámetros pasen a la interfaz, en lugar de al constructor, pero no querría que fuera estática.
fuente
¿Puede su clase hacerse estática?
Si es así, lo convertiría en una clase de 'Utilidades' en la que pondría todas mis clases de una función.
fuente
Si este método no tiene estado y no necesita pasarlo, entonces tiene más sentido definirlo como estático. Si necesita pasar el método, podría considerar usar un delegado en lugar de uno de sus otros enfoques propuestos.
fuente
Para aplicaciones simples y
internal
ayudantes, usaría un método estático. Para aplicaciones con componentes, me encanta el Marco de Extensibilidad Administrada . Aquí hay un extracto de un documento que estoy escribiendo para describir los patrones que encontrarás en mis API.I[ServiceName]Service
interfaz.Como un ejemplo artificial:
fuente
Simplemente haría todo en el constructor. al igual que:
o
fuente
Una cuestión más importante a considerar es si el sistema se estaría ejecutando en un entorno multiproceso y si sería seguro para subprocesos tener un método estático o variables ...
Debe prestar atención al estado del sistema.
fuente
Es posible que pueda evitar la situación todos juntos. Intenta refactorizar para obtener
arg1.myMethod1(arg2, arg3)
. Cambie arg1 con arg2 o arg3 si tiene más sentido.Si no tienes control sobre la clase de arg1, decóralo:
El razonamiento es que, en OOP, los datos y los métodos que procesan esos datos van juntos. Además, obtienes todas las ventajas que Mark mencionó.
fuente
Creo que si las propiedades de su clase o la instancia de clase no se utilizarán en los constructores o en sus métodos, no se sugiere que los métodos se diseñen como un patrón 'estático'. El método estático siempre debe pensarse en forma de "ayuda".
fuente
Dependiendo de si solo quieres hacer algo o hacer y devolver algo, puedes hacer esto:
fuente