gpt4 book ai didi

java - 如何在访问者模式中使用检查异常

转载 作者:太空狗 更新时间:2023-10-29 22:47:16 24 4
gpt4 key购买 nike

假设我有一套接受访问者的类(访问者模式),但由于这些类或特定访问者的性质,对它们执行操作可能会抛出已检查的异常。

访客接受界面:

public interface Mammal
{
void accept(MammalVisitor visitor);
}

访客界面:

public interface MammalVisitor
{
void visit(Cat m);
void visit(Dog m);
void visit(Cow m);
}

以及 Mammal 的实现:

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。我不能在每个访问方法上都声明抛出,因为它没有在访问者界面中声明。

我考虑过的解决方案:

  • Mammal.accept()、所有三个 MammalVisitor.visit() 和所有三个 MammalPrinter 上声明 throw IOException。访问()
    • 非常令人讨厌:Mammal 和 MammalVisitor 接口(interface)现在意识到它们涉及 IO 的潜在用途,这与使用访问者模式的整个要点背道而驰。
  • Mammal.accept() 和所有三个MammalVisitor.visit() 上声明throws Throwable,并声明throws IOException 在所有三个 MammalPrinter.visit()
    • 比上述解决方案更好:Mammal 和 MammalVisitor 现在用法不可知。然而,它们现在使用起来也很笨拙:没有抛出异常的访问者仍然被迫从 accept() 方法处理 Throwable。

我还有另外两个解决方案比上面的解决方案更受青睐,我将用它们来 self 回答我的帖子。我想看看哪一个受到广大社区的青睐。

最佳答案

我正要提到未经检查的包装重新 throw 方法,但 Giodude 抢在我前面。相反,我会建议另一种方法,我称之为礼貌异常(exception)(因为它作为对实现者的礼貌集成在接口(interface)中)。

在设计 visitor 和 Mammal 界面时,我将它们装备起来以处理用户选择的一个异常。访客:

public interface MammalVisitor<T extends Throwable>
{
void visit(Cat m) throws T;
void visit(Dog m) throws T;
void visit(Cow m) throws T;
}

和哺乳动物:

public interface Mammal
{
<T extends Throwable> void accept(MammalVisitor<T> visitor) throws T;
}

以及哺乳动物的实现:

public class Cat implements Mammal
{
@Override
public <T extends Throwable> void accept(MammalVisitor<T> visitor) throws T
{
visitor.visit(this);
}
}

Dog 和 Cow 的实现方式相同。打印访问者:

public class MammalPrinter implements MammalVisitor<IOException>
{
private final Appendable out;

public MammalPrinter(Appendable out)
{
this.out = out;
}

@Override
public void visit(Cat m) throws IOException
{
out.append("I'm a cat");
}

@Override
public void visit(Dog m) throws IOException
{
out.append("I'm a dog");
}

@Override
public void visit(Cow m) throws IOException
{
out.append("I'm a cow");
}
}

和用法:

Mammal m = MammalFactory.getMammal();
MammalPrinter mp = new MammalPrinter(System.out);
try
{
m.accept(mp);
}
catch (IOException e)
{
System.err.println("An IOException occurred");
}

从最终用户的角度来看,这会带来更加直观和易于实现的用法。

使用这种模式,如果访问者没有要抛出的已检查异常,他们会在其实现中指定一些未检查异常作为通用异常:

public class MammalPrinter implements MammalVisitor<RuntimeException>
{

当使用上述访问者调用 Mammal.accept() 时,不需要捕获来确保句法正确。也许您可以通过扩展具有私有(private)构造函数的名为“NeverThrown”的 RuntimeException 来进一步提高可读性。

关于java - 如何在访问者模式中使用检查异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19841946/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com