gpt4 book ai didi

java - 从访问者返回一个值

转载 作者:行者123 更新时间:2023-11-29 04:33:28 27 4
gpt4 key购买 nike

假设我们有以下我们无法更改的类:

interface Base {
void accept(Visitor visitor);
}

class Foo implements Base {
short getShortValue() {
return 1;
}

@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

class Bar implements Base {
int getIntValue() {
return 2;
}

@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

interface Visitor {
void visit(Foo foo);

void visit(Bar bar);
}

我们需要实现方法:

 int getValue(Base base)

访问者使用一些存储对象有很多可能性:

int useArray(Base base) {
int[] result = new int[1];

base.accept(new Visitor() {
@Override
public void visit(Foo foo) {
result[0] = foo.getShortValue();
}

@Override
public void visit(Bar bar) {
result[0] = bar.getIntValue();
}
});

return result[0];
}

int useAtomic(Base base) {
AtomicInteger result = new AtomicInteger();

base.accept(new Visitor() {
@Override
public void visit(Foo foo) {
result.set(foo.getShortValue());
}

@Override
public void visit(Bar bar) {
result.set(bar.getIntValue());
}
});

return result.intValue();
}

int useMutable(Base base) {
MutableInteger result = new MutableInteger(0);

base.accept(new Visitor() {
@Override
public void visit(Foo foo) {
result.setValue(foo.getShortValue());
}

@Override
public void visit(Bar bar) {
result.setValue(bar.getIntValue());
}
});

return result.getValue();
}

或者变态的东西:

int useException(Base base) {
class GotResult extends RuntimeException {
private final int value;

public GotResult(int value) {
this.value = value;
}
}

try {
base.accept(new Visitor() {
@Override
public void visit(Foo foo) {
throw new GotResult(foo.getShortValue());
}

@Override
public void visit(Bar bar) {
throw new GotResult(bar.getIntValue());
}
});
} catch (GotResult result) {
return result.value;
}

throw new IllegalStateException();
}

或者根本不使用访问者:

int useCast(Base base) {
if (base instanceof Foo) {
return ((Foo) base).getShortValue();
}
if (base instanceof Bar) {
return ((Bar) base).getIntValue();
}
throw new IllegalStateException();
}

这些是我们现在唯一的选择吗?我们有 Java 8(很快就会有 9),但仍在编写这些丑陋且容易出错的代码。 :)

最佳答案

我同意,从安全使用的角度来看,无法从访问者那里返回值是很糟糕的。

为了避免你上面演示的体操负担,你最好的选择是创建一个包装器类型来公开一个合理的 API(基于 corrected visitor pattern )以便脏工作只完成一次:当转换 Base 值到该包装器类型。

这里是你如何做到的:

interface BaseW {

interface Cases<X> {
X foo(Foo foo);
X bar(Bar bar);
}

<X> X match(Cases<X> cases);
//or alternatively, use a church encoding:
//<X> X match(Function<Foo, X> foo, Function<Bar, X> bar);

default Base asBase() {
return match(new Cases<Base>() {
@Override
public Base foo(Foo foo) {
return foo;
}

@Override
public Base bar(Bar bar) {
return bar;
}
});
}

static BaseW fromBase(Base base) {
return new Visitor() {
BaseW baseW;
{
base.accept(this);
}
@Override
public void visit(Foo foo) {
baseW = new BaseW() {
@Override
public <X> X match(Cases<X> cases) {
return cases.foo(foo);
}
};
}

@Override
public void visit(Bar bar) {
baseW = new BaseW() {
@Override
public <X> X match(Cases<X> cases) {
return cases.bar(bar);
}
};
}
}.baseW;
}

static int useCorrectedVisitor(Base base) {
return fromBase(base).match(new Cases<Integer>() {
@Override
public Integer foo(Foo foo) {
return (int) foo.getShortValue();
}

@Override
public Integer bar(Bar bar) {
return bar.getIntValue();
}
});
// or, if church encoding was used:
// return fromBase(base).match(
// foo -> (int) foo.getShortValue(),
// bar -> bar.getIntValue()
// );
}
}

现在(不要脸的插件),如果你不介意用derive4j (一个 jsr 269 代码生成器)上面的代码可以简化一点,同时改进语法:

@org.derive4j.Data // <- generate an BaseWs classe that allows handling
// of the interface as an algebraic data type.
interface BaseW {

interface Cases<X> {
X foo(Foo foo);
X bar(Bar bar);
}

<X> X match(Cases<X> cases);

default Base asBase() {
return match(BaseWs.cases(f -> f, b -> b));
}

static BaseW fromBase(Base base) {
return new Visitor() {
BaseW baseW;
{
base.accept(this);
}
@Override
public void visit(Foo foo) {
baseW = BaseWs.foo(foo);
}

@Override
public void visit(Bar bar) {
baseW = BaseWs.bar(bar);
}
}.baseW;
}

static int useStructuralPatternMatching(Base base) {
return BaseWs.caseOf(fromBase(base))
.foo(foo -> (int) foo.getShortValue())
.bar(Bar::getIntValue);
}
}

关于java - 从访问者返回一个值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42823571/

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