A veces creo clases de 'Util' que sirven principalmente para contener métodos y valores que realmente no parecen pertenecer a otra parte. Pero cada vez que creo una de estas clases, pienso "uh-oh, me arrepentiré más tarde ...", porque leí en alguna parte que es malo.
Pero, por otro lado, parece haber dos casos convincentes (al menos para mí) para ellos:
- secretos de implementación que se usan en varias clases dentro de un paquete
- Proporciona funcionalidades útiles para aumentar una clase, sin saturar su interfaz.
¿Estoy en camino a la destrucción? Que dices !! ¿Debo refactorizar?
Util
en los nombres de tus clases. Problema resuelto.SomethingUtil
es un poco vago y solo oscurece el verdadero propósito de la clase, lo mismo con las clases nombradasSomethingManager
oSomethingService
. Si esa clase tiene una sola responsabilidad, debería ser fácil darle un nombre significativo. Si no, ese es el verdadero problema con el que lidiar ...Util
, aunque, obviamente, no esperaba que eso conseguiría fijado en y el resto de la pregunta ignorado ...Respuestas:
El diseño moderno de OO acepta que no todo es un objeto. Algunas cosas son comportamientos, o fórmulas, y algunas de ellas no tienen estado. Es bueno modelar estas cosas como funciones puras para obtener el beneficio de ese diseño.
Java y C # (y otros) requieren que hagas una clase util y saltes ese aro para hacerlo. Molesto, pero no el fin del mundo; y no realmente problemático desde una perspectiva de diseño.
fuente
Nunca digas nunca"
No creo que sea necesariamente malo, solo es malo si lo haces mal y abusas de él.
Todos necesitamos herramientas y utilidades
Para empezar, todos usamos algunas bibliotecas que a veces se consideran casi ubicuas y imprescindibles. Por ejemplo, en el mundo Java, Google Guava o algunos de Apache Commons ( Apache Commons Lang , Apache Commons Collections , etc.).
Entonces claramente hay una necesidad de estos.
Evite las palabras difíciles, la duplicación y la introducción de errores
Si se piensa en ellas se encuentran prácticamente sólo un gran manojo de estas
Util
clases que usted describe, excepto que alguien pasó por un gran esfuerzo para conseguir que la derecha (relativamente), y han sido tiempo - probados y fuertemente ojo en ovillo por otros.Entonces, diría que la primera regla general cuando sientas ganas de escribir una
Util
clase es verificar queUtil
clase en realidad no exista.El único contraargumento que he visto para eso es cuando quieres limitar tus dependencias porque:
Pero ambos pueden abordarse volviendo a empaquetar la biblioteca con ProGuard o un equivalente, o desarmándola usted mismo (para los usuarios de Maven , el complemento maven-shade-plugin ofrece algunos patrones de filtrado para integrar esto como parte de su compilación).
Entonces, si está en una biblioteca y coincide con su caso de uso, y ningún punto de referencia le dice lo contrario, úselo. Si varía un poco de lo que usted extiende, extiéndalo (si es posible) o extiéndalo, o en el último recurso, vuelva a escribirlo.
Convenciones de nombres
Sin embargo, hasta ahora en esta respuesta los llamé
Util
s como tú. No les digas eso.Dales nombres significativos. Tome Google Guava como un (muy, muy) buen ejemplo de qué hacer, e imagine que el
com.google.guava
espacio de nombres es realmente suutil
raíz.Llame a su paquete
util
, en el peor de los casos, pero no a las clases. Si se trata deString
objetos y manipulación de construcciones de cadenas, llámeloStrings
, noStringUtils
(lo siento, Apache Commons Lang , ¡todavía me gusta y lo uso!). Si hace algo específico, elija un nombre de clase específico (comoSplitter
oJoiner
).Prueba de unidad
Si tiene que recurrir a escribir estas utilidades, asegúrese de realizar una prueba unitaria. Lo bueno de las utilidades es que generalmente son componentes bastante independientes, que toman entradas específicas y devuelven salidas específicas. Ese es el concepto. Así que no hay excusa para no probarlos en la unidad.
Además, las pruebas unitarias le permitirán definir y documentar el contrato de su API. Si las pruebas se rompen, o cambiaste algo de la manera incorrecta, o significa que estás tratando de cambiar el contrato de tu API (o que tus pruebas originales fueron basura, aprende de ello y no lo vuelvas a hacer) .
Diseño API
Las decisiones de diseño que tomará para estas API lo seguirán durante mucho tiempo, posiblemente. Entonces, si bien no pasa horas escribiendo un
Splitter
clon, tenga cuidado con la forma en que aborda el problema.Hágase algunas preguntas:
Desea que estas utilidades cubran una gran variedad de casos de uso, que sean robustas, estables, bien documentadas, que sigan el principio de menor sorpresa y que sean independientes. Idealmente, cada subpaquete de sus utilidades, o al menos todo su paquete de utilidades, se podrá exportar a un paquete para una fácil reutilización.
Como de costumbre, aprende de los gigantes aquí:
util
paquete de Java (que contiene la biblioteca de Colecciones) y su equivalente .Net ,Sí, muchos de estos hacen hincapié en las colecciones y las estructuras de datos, pero no me digas que no es dónde o para qué es probable que implementes la mayoría de tus utilidades, directa o indirectamente.
fuente
If deals with String objects and manipulation of string constructs, call it Strings, not StringUtils
StringsCollectionTypeHere
si desea una implementación concreta. O un nombre más específico si estas cadenas tienen un significado específico en el contexto de su aplicación. Para este caso particular, Guava usaStrings
para sus ayudantes relacionados con cuerdas, a diferencia deStringUtils
Commons Lang. Me parece perfectamente aceptable, solo significa para mí que las clases manejanString
objetos o es una clase de propósito general para administrar cadenas.NameUtils
cosas me molestan porque si se encuentra bajo un nombre de paquete claramente etiquetado, ya sabría que es una clase de utilidad (y si no, lo resolvería rápidamente al mirar la API). Es tan molesto para mí como la gente declarando cosas comoSomethingInterface
,ISomething
oSomethingImpl
. Estaba bastante de acuerdo con tales artefactos cuando codificaba en C y no usaba IDEs. Hoy, generalmente, no necesito esas cosas.Las clases de util no son cohesivas y, en general, tienen un diseño incorrecto porque una clase tiene que tener una sola razón para cambiar (Principio de responsabilidad única).
Sin embargo, he visto "util" clases en el API de Java, como:
Math
,Collections
yArrays
.Estas son, de hecho, clases de utilidad, pero todos sus métodos están relacionados con un solo tema, uno tiene operaciones matemáticas, uno tiene métodos para manipular colecciones y el otro para manipular matrices.
Intente no tener métodos totalmente no relacionados en una clase de utilidad. Si ese es el caso, lo más probable es que también puedas ponerlos en otro lugar donde realmente pertenecen.
Si debe tener util clases luego probarlos a estar separados por el tema como Java
Math
,Collections
yArrays
. Al menos, muestra cierta intención de diseño incluso cuando son solo espacios de nombres.Por mi parte, siempre evito las clases de utilidad y nunca he tenido la necesidad de crear una.
fuente
Math
oArrays
muestra al menos alguna intención de diseño.Es perfectamente aceptable tener clases de utilidad , aunque prefiero el término
ClassNameHelper
. El .NET BCL incluso tiene clases auxiliares. Lo más importante para recordar es documentar minuciosamente el propósito de las clases, así como cada método auxiliar individual, y hacer que sea un código mantenible de alta calidad.Y no te dejes llevar por las clases de ayuda.
fuente
Yo uso un enfoque de dos niveles. Una clase "Globals" en un paquete (carpeta) "util". Para que algo entre en una clase "Globals" o paquete "util", debe ser:
Ejemplos que pasan estas pruebas:
Aquí hay un ejemplo de un método auxiliar muy pequeño, completamente independiente del resto de la aplicación:
Mirando esto, puedo ver un error que 21 debería ser "21", 22 debería ser "22", etc. pero eso no viene al caso.
Si uno de esos métodos auxiliares crece o se complica, se debe mover a su propia clase en el paquete util. Si dos o más clases auxiliares en el paquete util están relacionadas entre sí, se deben trasladar a su propio paquete. Si un método constante o auxiliar resulta estar relacionado con una parte específica de su aplicación, debe moverse allí.
Debería poder justificar por qué no hay un mejor lugar para todo lo que pega en una clase de Globals o paquete de utilidades y debe limpiarlo periódicamente utilizando las pruebas anteriores. De lo contrario, solo estás creando un desastre.
fuente