Предположим, что у меня есть набор классов, которые принимают посетителя (шаблон посетителя), но из-за характера этих классов или конкретного посетителя, работа над ними, вероятно, будет способна выбрасывать проверенное исключение.
Пользовательский интерфейс:
public interface Mammal
{
void accept(MammalVisitor visitor);
}
Интерфейс посетителя:
public interface MammalVisitor
{
void visit(Cat m);
void visit(Dog m);
void visit(Cow m);
}
И реализации млекопитающих:
public class Cat implements Mammal
{
public void accept(MammalVisitor visitor)
{
visitor.visit(this);
}
}
Мы предположим, что Dog и Cow реализованы идентично Cat
Теперь предположим, что мой посетитель:
public class MammalPrinter implements MammalVisitor
{
private final Appendable out;
public MammalPrinter(Appendable out)
{
this.out = out;
}
@Override
public void visit(Cat m)
{
out.append("I'm a cat");
}
@Override
public void visit(Dog m)
{
out.append("I'm a dog");
}
@Override
public void visit(Cow m)
{
out.append("I'm a cow");
}
}
И я печатаю результат в stdio:
Mammal m = MammalFactory.getMammal();
MammalPrinter mp = new MammalPrinter(System.out);
m.accept(mp);
Однако, MammalPrinter выше синтаксически некорректен, потому что Appendable.append(String) выбрасывает java.io.IOException
. Я не могу объявить бросок для каждого метода посещения, потому что он не объявлен в интерфейсе посетителя.
Решения, которые я рассмотрел:
- Объявите
throws IOException
наMammal.accept()
, все триMammalVisitor.visit()
и все триMammalPrinter.visit()
- Очень сомнительно: интерфейсы Mammal и MammalVisitor теперь знают о своем потенциальном использовании с использованием IO, что противоречит целям использования шаблона посетителя.
- Объявите
throws Throwable
наMammal.accept()
и всех трехMammalVisitor.visit()
и объявитеthrows IOException
на всех трехMammalPrinter.visit()
- Лучше, чем указанное решение: Mammal и MammalVisitor теперь являются агностиками. Тем не менее, они также теперь громоздки для использования: посетители, которые не исключают исключений, по-прежнему вынуждены обрабатывать Throwable из метода accept().
У меня есть два других решения, которые я одобряю выше, с которыми я сам отвечу на мой пост. Я хотел бы видеть, какой из них предпочитает сообщество в целом.