2009-11-04 19 views
11

He estado leyendo que la creación de dependencias mediante el uso de clases estáticas/singletons en el código, es mala forma y crea problemas, es decir. acoplamiento hermético y pruebas unitarias.Clases de utilidades .. ¿Bueno o malo?

Tengo una situación en la que tengo un grupo de métodos de análisis de URL que no tienen ningún estado asociado a ellos, y realizo operaciones usando solo los argumentos de entrada del método. Estoy seguro de que estás familiarizado con este tipo de método.

En el pasado habría procedido a crear una clase y agregar estos métodos y llamarlos directamente desde mi código, por ejemplo.

UrlParser.ParseUrl(url); 

Pero espere un minuto, que es la introducción de una dependencia a otra clase. No estoy seguro de si estas clases de "utilidad" son malas, ya que son apátridas y esto minimiza algunos de los problemas con dichas clases estáticas y singletons. ¿Alguien podría aclarar esto?

Debo mover los métodos a la clase de llamada, es decir, si solo la clase de llamada utilizará el método. Esto puede violar el 'Principio de Responsabilidad Individual'.

+0

"Tengo una situación en la que tengo un grupo de métodos de análisis de la URL que no tienen un estado asociado con ellos, y realizan operaciones utilizando sólo los argumentos de entrada del método. Estoy seguro de que está familiarizado con este tipo de método". tales métodos se denominan funciones puras – morphles

+0

comprobar esta entrada del blog (hablando principalmente acerca de Java, pero sigue siendo relevante aquí): http://www.yegor256.com/2014/05/05/oop-alternative-to-utility-classes. html – yegor256

Respuesta

7

Desde el punto de vista del diseño teórico, creo que las clases de utilidad son algo que debe evitarse cuando sea posible. Básicamente no son diferentes a las clases estáticas (aunque son un poco más agradables, ya que no tienen ningún estado).

Desde un punto de vista práctico, sin embargo, los creo, y aliento su uso cuando corresponda. Tratar de evitar las clases de utilidad es a menudo engorroso y conduce a un código menos sostenible. Sin embargo, intento alentar a mis desarrolladores a evitar estos en las API públicas cuando sea posible.

Por ejemplo, en su caso, creo que UrlParser.ParseUrl (...) probablemente se maneje mejor como clase. Mire System.Uri en el BCL: maneja una interfaz limpia y fácil de usar para Uniform Resource Indentifiers, que funciona bien y mantiene el estado real. Prefiero este enfoque a un método de utilidad que funciona en cadenas y obliga al usuario a pasar una cadena, recuerde validarlo, etc.

+0

Buen punto. System.Uri es un buen ejemplo de cómo convertir un método de utilidad estático como este en un objeto. –

+0

También es muy relevante a su pregunta específica, dada su ejemplo;) –

+0

Un ejemplo bastante malo como System.Uri se sabe que está plagada de problemas relacionados con la representación original de cadena y conversiones a/desde las rutas relativas absolutos. Esto es lo que sucede en cada diseño de abstracción y formulación de API, nunca lo sacas de la caja, y con los diseñadores de frameworks de MSFT toma años acertar y a menudo causa más complicaciones que con métodos estáticos que son fáciles y conocidos por ser funcional en la naturaleza Pero eso es un problema con el 'marco' y el enfoque manía 'directrices de diseño' en general .. –

0

Están bien siempre que los diseñe bien (es decir, no es necesario que cambie su firma de vez en cuando).

Estos métodos de utilidad no cambian con frecuencia, porque hacen una sola cosa. El problema surge cuando quieres ajustar un objeto más complejo a otro. Si uno de ellos necesita cambiar o ser reemplazado, será más difícil hacerlo si los tiene altamente acoplados.

Dado que estos métodos de utilidad no cambiarán tan a menudo, diría que no hay mucho problema.

Creo que sería peor si copia/pega el mismo método de utilidad una y otra vez.

Este video How to design a good API and why it matters de Joshua Bloch, explica varios conceptos a tener en cuenta al diseñar una API (que sería su biblioteca de utilidades). Aunque es un reconocido arquitecto de Java, el contenido se aplica a todos los lenguajes de programación.

2

Las clases de utilidad están bien ... siempre que no violen los principios de diseño. Úselos tan felizmente como usaría las clases de framework principal.

Las clases deben ser bien nombradas y lógicas. Realmente no son tanto "utilidad" sino parte de un trabajo de campo emergente que las clases nativas no ofrecen.

Usar cosas como los métodos de extensión también pueden ser útiles para alinear la funcionalidad a la clase "correcta". PERO, pueden ser motivo de cierta confusión ya que las extensiones no están empaquetadas con la clase que suelen extender, lo que no es ideal, pero, aún así, puede ser muy útil y producir un código más limpio.

2

Siempre puede crear una interfaz y usarla con la inyección de dependencia con instancias de clases que implementan esa interfaz en lugar de clases estáticas.

La pregunta es, ¿realmente vale la pena el esfuerzo? En algunos sistemas, la respuesta es sí, pero en otros, especialmente en los más pequeños, la respuesta es probablemente no.

+0

Esto es lo que sugeriría también. Si el método de utilidad es complejo o computacionalmente costoso, sugeriría usar la inyección de dependencia para inyectarlo como un objeto de servicio de algún tipo. De lo contrario, no me preocuparía. –

+0

La inyección no elimina la dependencia. Simplemente hace que sea más fácil de manejar. – OscarRyz

+0

La única manera de ** eliminar ** una dependencia es eliminarla. No veo tu punto. –

1

Realmente, realmente trato de evitarlos, pero ¿a quién estamos engañando ... ellos se arrastran en cada sistema. Sin embargo, en el ejemplo dado utilizaría un objeto URL que expondría varios atributos de la URL (protocolo, dominio, ruta y parámetros de cadena de consulta). Casi cada vez que deseo crear una clase de utilidad de estática, puedo obtener más valor creando un objeto que realice este tipo de trabajo.

De manera similar he creado muchos controles personalizados que tienen validación incorporada para cosas como porcentajes, moneda, números de teléfono y similares. Antes de hacer esto, tenía una clase de utilidad de analizador que tenía todas estas reglas, pero hace que sea mucho más limpio simplemente colocar un control en la página que ya conoce las reglas básicas (y por lo tanto requiere solo lógica de negocio validación para ser adicional).

Todavía conservo la clase de utilidad del analizador y estos controles ocultan esa clase estática, pero úsala ampliamente (manteniendo todo el análisis en un lugar fácil de encontrar). En ese sentido, considero aceptable tener la clase de utilidad porque me permite aplicar "No repetir", mientras obtengo el beneficio de clases instanciadas con los controles u otros objetos que usan las utilidades.

1

Estoy de acuerdo con algunas de las otras respuestas aquí que es el singleton clásico que mantiene una única instancia de un objeto con estado que debe evitarse y no necesariamente clases de utilidad sin ningún estado que sea malo. También estoy de acuerdo con Reed en que, si es posible, coloque estos métodos de utilidad en una clase en la que tenga sentido hacerlo y en la que lógicamente se sospeche que esos métodos residen. Yo agregaría, que a menudo estos métodos de utilidad estáticos podrían ser buenos candidatos para los métodos de extensión.

0

Úselos con moderación, quiere poner tanta lógica como sea posible en sus clases para que no se conviertan en contenedores de datos.

Pero, al mismo tiempo, no puede evitar las utilidades, a veces se requieren.

En este caso, creo que está bien.

FYI existe la clase system.web.httputility que contiene una gran cantidad de utilidades http comunes que pueden serle útiles.

1

Esto realmente depende del contexto y de cómo lo usemos.

Las clases de utilidad, en sí, no están nada mal. Sin embargo, se volverá malo si lo usamos mal. Cada patrón de diseño (especialmente el patrón Singleton) puede convertirse fácilmente en antipatrón, lo mismo ocurre con las clases de utilidad.

En el diseño de software, necesitamos un equilibrio entre la flexibilidad & simplicidad.Si vamos a crear un StringUtils que sólo es responsable de la cadena de manipulación:

  • ¿Viola SRP (Responsabilidad Individual) Principio? -> No, son los desarrolladores quienes ponen demasiadas responsabilidades en las clases de utilidad que violan a SRP.
  • "No se puede inyectar usando DI marcos" -> son la aplicación StringUtils va varía? ¿Vamos a cambiar sus implementaciones en tiempo de ejecución? ¿Nos vamos a burlar? Por supuesto no.

=> Las clases de utilidad, themselve, no están nada mal. Es culpa de los desarrolladores lo que lo hace malo.

Realmente todo depende del contexto. Si solo vas a crear una clase de utilidad que solo contenga una sola responsabilidad, y solo se usa de forma privada dentro de un módulo o una capa. Entonces todavía eres bueno con eso.

Cuestiones relacionadas