Сначала немного фона:
У меня уже есть класс Result, который я реализовал для переноса информации о результатах. Они были реализованы специально для сбоев, результат успеха, как правило, не несет никакой дополнительной информации. Я использую их в общедоступных методах вне основного API в одном из моих проектов или в методах глубиной в один или два уровня, где мне нужно перенести подробную информацию обратно в общедоступный API. Этот API используется в контейнере и клиенте командной строки и ранее был очень хорошо проверен. Альтернативой было добавление этой информации контекста сбоя к исключениям и добавление нескольких более отдельных классов исключений, где они просто не принадлежали. Я думаю, это отражает мой общий подход:
http://blogs.atlassian.com/2011/05/exceptions_are_bad
Результат имеет вспомогательное перечисление и интерфейс:
- ResultStatus: SUCCESS, FAILURE, CONDITIONAL_SUCCESS и т. Д. Содержит коды возврата int и общие сообщения (например, «Операция прошла успешно»)
- ResultCode: пустой интерфейс для маркировки кодов результатов перечисления, FILE_NOT_FOUND, FILE_INVALID, FILE_INCOMPATIBLE. В основном они предназначены для модульного и функционального тестирования, но также используются для интерактивной справки (справка Maven по сбою функционально аналогична тому, что я делаю)
Result предоставляет статические фабричные методы для статуса и методы компоновщика для установки других ключевых полей и является неизменным. Вот как выглядит результат построения:
Result.success().withCode( ResultCode ).withMessage( "" );
И оценивая полученный результат:
result.isSuccessful();
result.hasCode( ResultCode );
result.getMessage();
Моя проблема:
Подход оказался очень успешным, в частности, благодаря функциональным тестам стало легче, однако у меня есть один существенный пробел: хотя в большинстве случаев я забочусь только о результате, в некоторых критических областях мне нужно возвращать значение с результатом ,
Я не доволен своей первой попыткой: ResultPair<T>
, которая содержит результат и значение, где T - тип значения. Если я не продублирую все методы Result, использование класса является многословным и неуклюжим: получите Result, добавьте его в ResultPair и выловите результат и значение перед оценкой. На первый взгляд, наследование не будет работать из-за паттерна компоновщика, и я не могу придумать, как получить чистый, чистый код, который Result позволяет без полного дублирования класса Result.
В идеале, подход позволил бы Result возвращать значение опционально, но я не могу придумать способ сделать это безопасным для типов способом, который гарантирует, что сигнатуры метода четко указывают тип значения, но избегают бессмысленного универсальный параметр везде, где я не возвращаю значение.
Я действительно не против иметь два класса, и это не конец света, чтобы дублировать Result Builder и оценочный код, он просто чувствует неправильно , и я чувствую, что отсутствие опыта приобретает лучше меня, и я пропускаю (очевидное или не очень очевидное) решение. Я использую Guava, и я хочу запретить нулевые значения дружественным способом, поэтому может дополнительно обернуть все значения в необязательные, но мне все еще нужны общие параметры (и объединить их в класс, чтобы избежать result.value ( ) .get () ... Хорошо, теперь я думаю вслух. Я должен задать вопрос ...).
Есть ли способ удовлетворить эти, по-видимому, взаимоисключающие требования?