Сначала немного предыстории:
У меня уже есть класс Result, который я реализовал для передачи информации о результате. Они были реализованы специально для неудач, успешный результат обычно не несет никакой дополнительной информации. Я использую их в публичных методах на внешней стороне основного API в одном из моих проектов, или в методах на один или два уровня глубже, где мне нужно передать подробную информацию обратно в публичный API. Этот API используется в контейнере и клиенте командной строки, и ранее он был очень счастлив к исключениям. Альтернативой было добавление этой информации о контексте сбоя в исключения и добавление еще нескольких отдельных классов исключений, где им просто не место. Думаю, это отражает мой общий подход:
http://blogs.atlassian.com/2011/05/exceptions_are_bad
Result имеет поддерживающие перечисления и интерфейс:
Result предоставляет статические методы фабрики для статуса и методы конструктора для установки других ключевых полей и является неизменяемым. Вот как выглядит создание результата:
Result.success().withCode( ResultCode ).withMessage( "" );
И оценка возвращаемого результата:
result.isSuccessful();
result.hasCode( ResultCode );
result.getMessage();
Моя проблема:
Подход оказался очень удачным, в частности, функциональные тесты стали простым делом, однако у меня есть один серьезный пробел: хотя в большинстве случаев меня интересует только результат, в некоторых критических областях мне нужно возвращать значение вместе с результатом.
Я недоволен своей первой попыткой: ResultPair
, который содержит результат и значение, где T - тип значения. Если я не продублирую все методы Result, использование класса будет многословным и неуклюжим: получить Result, добавить его в ResultPair, выловить результат и значение перед оценкой. На первый взгляд, наследование не работает из-за паттерна builder, и я не могу придумать способ получить ясный, чистый код, который позволяет Result, без полного дублирования класса Result.
В идеале, подход должен позволить Result возвращать значение опционально, но я не могу придумать, как сделать это безопасным для типов способом, чтобы сигнатуры методов четко указывали тип значения, но при этом избежать бессмысленного общего параметра везде, где я не возвращаю значение.
Я действительно не против иметь два класса, и это не конец света - дублировать код построения и оценки результата, просто это кажется неправильным, и я чувствую, что недостаток опыта берет надо мной верх, и я упускаю (очевидное или не очень очевидное) решение. Я использую Guava и хочу дружелюбно запретить нулевые значения, поэтому могу дополнительно обернуть все значения в Optional, но мне все равно понадобятся общие параметры (и компоновать их в класс, чтобы избежать result.value().get()...). Ладно, теперь я думаю вслух. Я должен задать вопрос...).
Есть ли способ удовлетворить эти, казалось бы, взаимоисключающие требования?