2012-01-13 7 views
6

Primero algunos antecedentes:¿Cómo devuelvo los detalles de falla de un método sin usar excepciones y opcionalmente incluyo un valor?

Ya tengo una clase de resultado que he implementado para llevar la información del resultado. Se implementaron particularmente por fallas, un resultado exitoso generalmente no conlleva información adicional. Los uso en métodos públicos fuera de una API principal en uno de mis proyectos, o en métodos de una o dos capas de profundidad donde necesito llevar la información detallada de vuelta a la API pública. Esta API se consume en el contenedor y en un cliente de línea de comandos y fue una excepción muy comprobada muy contento. La alternativa era agregar esta información de contexto de falla a las excepciones y agregar varias clases de excepción más distintas, donde simplemente no pertenecían. Creo que esto refleja mi enfoque general:

http://blogs.atlassian.com/2011/05/exceptions_are_bad

El resultado tiene una enumeración de apoyo y la interfaz:

  1. ResultStatus: éxito, fracaso, etc. Tomas CONDITIONAL_SUCCESS códigos de retorno int y mensajes genéricos (por ejemplo " La operación fue exitosa ")
  2. ResultCode: interfaz vacía para etiquetar códigos de resultado enum, FILE_NOT_FOUND, FILE_INVALID, FILE_INCOMPATIBLE. Estos son en su mayoría para la unidad y pruebas funcionales, pero también se utilizan para la ayuda en línea (la ayuda de Maven en caso de fallo es funcionalmente similar a lo que estoy haciendo)

resultado proporciona métodos estáticos de fábrica para el estado, y los métodos constructor para establece los otros campos clave y es inmutable. Esto es lo que la construcción de un resultado es idéntico:

Result.success().withCode(ResultCode).withMessage(""); 

y evaluar el resultado devuelto:

result.isSuccessful(); 
result.hasCode(ResultCode); 
result.getMessage(); 

Mi problema:

El enfoque ha tenido mucho éxito, sobre todo haciendo pruebas funcionales de una brisa, sin embargo Tengo una brecha importante: aunque en la mayoría de los casos solo me importa el resultado, en algunas áreas críticas necesito devolver un valor con el resultado.

No estoy contento con mi primer intento: ResultPair<T> que contiene el resultado y el valor donde T es el tipo del valor. A menos que duplique todos los métodos de resultado, usar la clase es detallado y torpe: obtener un resultado, agregarlo a un par de resultados, pescar el resultado y valorar antes de evaluar. A primera vista, la herencia no funcionará debido al patrón del generador y no puedo pensar en la forma de obtener un código claro y limpio que el resultado permita sin duplicar por completo la clase del resultado.

Idealmente, el enfoque permitiría a Result devolver un valor opcionalmente, pero no puedo pensar en una forma de hacerlo de forma segura que asegure que las firmas de métodos indiquen claramente el tipo de valor, pero evita tener un Parámetro genérico sin sentido en todos lados No devuelvo un valor.

Realmente no me importa tener dos clases y no es el fin del mundo para duplicar el constructor de resultados y código de evaluación, sólo se siente mal y me siento como una falta de experiencia es conseguir lo mejor de mí y me falta una solución (obvia o no tan obvia). Estoy usando Guava y querré rechazar valores nulos de forma amistosa, por lo que también puedo incluir todos los valores en un Opcional, pero aún necesitaría parámetros genéricos (y los escribiría en la clase para evitar result.value () .get() ... Está bien, ahora estoy pensando en voz alta. Debería hacer una pregunta ...).

¿Hay alguna manera de cumplir estos requisitos aparentemente mutuamente excluyentes?

+0

+1 Un compañero de trabajo hizo algo muy similar para nuestro código y ayuda mucho. – user949300

Respuesta

2

Usted puede crear su ResultPair<T> como clase base para el vacío de clase resultado :

public class Result extends ResultPair<Void> { ... } 

Todos los métodos pertinentes sería declarado en ResultPair<T>.

ACTUALIZACIÓN:

Mejor aún, tiene apenas un tipo Result<T>, y utilizar Result<Void> cada vez que no quiere tener un valor de retorno. O más bien, si usa Void como un argumento tipo le parece extraño, cree un nuevo tipo no desinstalable (o singleton) que signifique "no hay resultado", y úsela en su lugar: Result<Unit>, por ejemplo.

+0

Eso no se me había ocurrido en absoluto, me olvidé por completo de Void. No puedo reducir la visibilidad del método heredado, lo que significaría métodos relacionados con el valor en la firma, pero supongo que los anularía y lanzaría IllegalStateExceptions. –

+0

Desafortunadamente, esto no lo hace. Los intentos de utilizar los métodos estáticos o de compilación que devuelven ResultPair provocarán desajustes de tipo con el resultado. Tendría que duplicar los métodos estáticos y emitir explícitamente a Result para los métodos de compilación. –

+0

Sí, eso está muy mal ... Creo que tendrá que duplicar esos métodos, pero trate de delegarlos _ tanto como sea posible_ a una implementación común, en otras palabras, refactorizarlos para disminuir la duplicación de código. –

Cuestiones relacionadas