В текущем проекте Java у нас есть код, подобный следующему примеру:
try {
doSomeThing(anObject);
}
catch (SameException e) {
// Do nothing or log, but don't abort current method.
}
try {
doOtherThing(anObject);
}
catch (SameException e) {
// Do nothing or log, but don't abort current method.
}
// ... some more calls to different method ...
try {
finallyDoYetSomethingCompletelyDifferent(anObject);
}
catch (SameException e) {
// Do nothing or log, but don't abort current method.
}
Как видите, несколько разных методов вызываются с одним и тем же объектом, и для каждого вызова одно и то же исключение перехватывается и обрабатывается одинаковым (или очень похожим) способом. Исключение не генерируется повторно, но может быть зарегистрировано и затем удалено.
Единственная причина, по которой в каждом отдельном методе есть try-catch
, состоит в том, чтобы всегда выполнять все методы, независимо от того, завершился ли ранее выполненный метод.
Мне не нравится приведенный выше код вообще. Он занимает много места, очень повторяется (особенно запись в журнале catch
; здесь не представлена) и выглядит просто плохо.
Я могу придумать несколько других способов написания этого кода, но они мне тоже не очень нравятся. Мне в голову пришли следующие варианты:
Последовательность петлевого переключателя / парадигма для конкретного случая
(см. Википедия или Ежедневный WTF )
for (int i = 0; i <= 9; i++) {
try {
switch (i) {
case 0:
doSomeThing(anObject); break;
case 1:
doOtherSomeThing(anObject); break;
// ...More cases...
case 9:
doYetSomethingCompletelyDifferent(anObject); break;
}
}
catch (SameException e) {
// Do nothing or log, but don't abort current method.
}
}
Это явно плохой код, очень подвержен ошибкам и выглядит дилетантским.
Отражение
Используйте отражение, чтобы получить Method
объекты для вызова методов и сохранить их в списке в порядке, в котором они должны быть выполнены. Затем выполните итерацию по этому списку и вызовите метод, используя anObject
в качестве единственного параметра. Исключение обрабатывается внутри цикла.
Мне не нравится этот подход, поскольку ошибки (например, опечатки в именах методов) появляются только во время выполнения, а API Reflection немного болтлив.
Functor
Создайте класс Functor следующим образом:
private class Functor
{
void doStuff(MyObject object) throws SameException;
}
Затем создайте список Functor
объектов, которые вызывают методы. Как это:
List<Functor> functors = new ArrayList<Functor>();
functors.add(new Functor() {
@Override
public void execute(MyObject anObject) {
doSomeThing(anObject);
}
});
functors.add(new Functor() {
@Override
public void execute(MyObject anObject) {
doOtherSomeThing(anObject);
}
});
Позже повторите этот список и вызовите execute()
для каждого Functor
объекта.
Я могу суммировать мои чувства по поводу этого подхода двумя словами: раздувание кода.
Поскольку мне не очень нравятся все четыре подхода, я хотел бы обсудить эту проблему здесь. Что вы считаете лучшим подходом? Как вы решали подобные проблемы в прошлом? Может быть, есть более простое решение, которое я пропустил полностью?