gpt4 book ai didi

java - Java中访客模式的通用实现

转载 作者:行者123 更新时间:2023-11-30 10:46:50 24 4
gpt4 key购买 nike

我进行了一些研究,试图开发一种类型转换框架,该框架提供了将源类实例(例如Foo)转换为结果类实例(例如Bar或Baz)的功能。该框架应该提供对同一对源和结果使用不同转换逻辑(即不同转换器)的能力。它也应该是可扩展的,即允许为源和结果的新对和现有对添加新的转换器。另一个要求是类型安全性,即在不使用转换器实现适当转换逻辑的情况下将某些源类的实例转换为结果类的实例的任何尝试都将导致编译时错误。

我决定使用Visitor pattern,将转换器用作Visitor,将可转换类用作Elements。为了提供可扩展性和类型安全性,我决定使用泛型。因此,我受到互联网上某篇文章的影响(不幸的是,我失去了链接)对转换框架的第一个实现是...

具有全状态转换器的转换框架

以下是框架的核心接口Converter和Convertable:

    public interface Converter<V extends Converter<V,A>, A extends Convertable<V,A>> {

void convert(A convertable);
}


public interface Convertable<V extends Converter<V,A>, A extends Convertable<V,A>> {

void convertWith(V converter);
}


泛型使 Convertable的实现仅接受可以转换它们的 Converter的实现,并使 Converter的实现仅访问要转换的 Convertable的实现。这是此类转换器的示例:

interface FooConverter extends Converter<FooConverter,Foo> {

void convert(Foo convertable);

void convert(FooChild1 convertable);

void convert(FooChild2 convertable);
}


public class Foo2BarConverter implements FooConverter {

private Bar result;

public Bar getResult() {
return result;
}

@Override
public void convert(Foo convertable) {
this.result = new Bar("This bar's converted from an instance of Foo");
}

@Override
public void convert(FooChild1 convertable) {
this.result = new Bar("This bar's converted from an instance of FooChild1");
}

@Override
public void convert(FooChild2 convertable) {
this.result = new Bar("This bar's converted from an instance of FooChild2");
}
}


public class Foo2BazConverter implements FooConverter {

private Baz result;

public Baz getResult() {
return result;
}

@Override
public void convert(Foo convertable) {
this.result = new Baz("This baz's converted from an instance of Foo");
}

@Override
public void convert(FooChild1 convertable) {
this.result = new Baz("This baz's converted from an instance of FooChild1");
}

@Override
public void convert(FooChild2 convertable) {
this.result = new Baz("This baz's converted from an instance of FooChild2");
}
}


以下是一些可以使用该转换器转换的类:

public class Foo implements Convertable<FooConverter, Foo> {

@Override
public void convertWith(FooConverter converter) {
converter.convert(this);
}
}


public class FooChild1 extends Foo {

@Override
public void convertWith(FooConverter converter) {
converter.convert(this);
}
}


public class FooChild2 extends Foo {

@Override
public void convertWith(FooConverter converter) {
converter.convert(this);
}
}


这是结果类,即 BarBaz

public class Bar {

private String message;

public Bar(String message) {
this.message = message;
}

public String getMessage() {
return message;
}
}


public class Baz {

private String message;

public Baz(String message) {
this.message = message;
}

public String getMessage() {
return message;
}
}


这是测试转换器的代码:

Foo fooObj = new Foo();
Foo fooChild1Obj = new FooChild1();
Foo fooChild2Obj = new FooChild2();

// converting to bar
Foo2BarConverter foo2BarConverter = new Foo2BarConverter();

fooObj.convertWith(foo2BarConverter);
System.out.println(foo2BarConverter.getResult().getMessage());

fooChild1Obj.convertWith(foo2BarConverter);
System.out.println(foo2BarConverter.getResult().getMessage());

fooChild2Obj.convertWith(foo2BarConverter);
System.out.println(foo2BarConverter.getResult().getMessage());

// converting to baz
System.out.println();
Foo2BazConverter foo2BazConverter = new Foo2BazConverter();

fooObj.convertWith(foo2BazConverter);
System.out.println(foo2BazConverter.getResult().getMessage());

fooChild1Obj.convertWith(foo2BazConverter);
System.out.println(foo2BazConverter.getResult().getMessage());

fooChild2Obj.convertWith(foo2BazConverter);
System.out.println(foo2BazConverter.getResult().getMessage());


并用此代码构建输出

This bar's converted from an instance of Foo
This bar's converted from an instance of FooChild1
This bar's converted from an instance of FooChild2

This baz's converted from an instance of Foo
This baz's converted from an instance of FooChild1
This baz's converted from an instance of FooChild2


看一下 resultFoo2BarConverter中的 Foo2BazConverter字段。那是实现的主要缺点。它使转换器充满状态,这并不总是方便的。为了避免这种缺陷,我开发了...

无需双重调度的转换框架

此实现的重点是对具有结果类的转换器进行参数设置,并从 convertConverter方法和 convertWithConvertable方法返回结果。这是它在代码中的外观:

public interface Converter<A extends Convertable<A>,R> {

R convert(A convertable);
}

public interface Convertable<A extends Convertable<A>> {

<R> R convertWith(Converter<A,R> converter);
}

public interface FooConverter<R> extends Converter<Foo,R> {

@Override
R convert(Foo convertable);

R convert(FooChild1 convertable);

R convert(FooChild2 convertable);
}

public class Foo2BarConverter implements FooConverter<Bar> {

@Override
public Bar convert(Foo convertable) {
return new Bar("This bar's converted from an instance of Foo");
}

@Override
public Bar convert(FooChild1 convertable) {
return new Bar("This bar's converted from an instance of FooChild1");
}

@Override
public Bar convert(FooChild2 convertable) {
return new Bar("This bar's converted from an instance of FooChild2");
}
}

public class Foo2BazConverter implements FooConverter<Baz> {

@Override
public Baz convert(Foo convertable) {
return new Baz("This baz's converted from an instance of Foo");
}

@Override
public Baz convert(FooChild1 convertable) {
return new Baz("This baz's converted from an instance of FooChild1");
}

@Override
public Baz convert(FooChild2 convertable) {
return new Baz("This baz's converted from an instance of FooChild2");
}
}

public class Foo implements Convertable<Foo> {

@Override
public <R> R convertWith(Converter<Foo,R> converter) {
return converter.convert(this);
}
}

public class FooChild1 extends Foo {

@Override
public <R> R convertWith(Converter<Foo,R> converter) {
return converter.convert(this);
}
}

public class FooChild2 extends Foo {

@Override
public <R> R convertWith(Converter<Foo,R> converter) {
return converter.convert(this);
}
}


VConvertable声明中删除,因为在 Converter声明中具有结果类实际上将使我们可以对带有结果类的 Convertable实现进行参数化。它将可转换的每个实现绑定到它可以转换为的唯一结果类。因此, convertWith中的 Convertable是指具有 Converter<A,R>接口的已接收转换器。这就是问题所在。现在,调用接收到的转换器的 Convertable实现将始终调用 convert接口中定义的 Converter,而不是 convert实现中覆盖它的 Converter方法。换句话说,将永远不会调用 convert(FooChild1 convertable)convert(FooChild2 convertable)中的 Foo2BarConverterFoo2BazConverter。基本上,它消除了访客模式的主要概念,即双重调度。这是一个测试代码...

Foo fooObj = new Foo();
Foo fooChild1Obj = new FooChild1();
Foo fooChild2Obj = new FooChild2();

// converting to bar
Foo2BarConverter foo2BarConverter = new Foo2BarConverter();
System.out.println(fooObj.convertWith(foo2BarConverter).getMessage());
System.out.println(fooChild1Obj.convertWith(foo2BarConverter).getMessage());
System.out.println(fooChild2Obj.convertWith(foo2BarConverter).getMessage());

System.out.println();

// converting to baz
Foo2BazConverter foo2BazConverter = new Foo2BazConverter();
System.out.println(fooObj.convertWith(foo2BazConverter).getMessage());
System.out.println(fooChild1Obj.convertWith(foo2BazConverter).getMessage());
System.out.println(fooChild2Obj.convertWith(foo2BazConverter).getMessage());


其输出表明在此实现中未调用重写方法。

This bar's converted from an instance of Foo
This bar's converted from an instance of Foo
This bar's converted from an instance of Foo

This baz's converted from an instance of Foo
This baz's converted from an instance of Foo
This baz's converted from an instance of Foo


下一个我试图用...制作无状态转换器的实现是...

参数化的转换器

这里的主要概念是仅参数化要返回转换结果而不参数化接口声明的方法。

public interface Converter<V extends Converter<V,A>, A extends Convertable<V,A>> {

<R> R convert(A convertable);
}

public interface Convertable<V extends Converter<V,A>, A extends Convertable<V,A>> {

<R> R convertWith(V converter);
}

interface FooConverter extends Converter<FooConverter,Foo> {

<R> R convert(Foo convertable);

<R> R convert(FooChild1 convertable);

<R> R convert(FooChild2 convertable);
}

public class Foo2BarConverter implements FooConverter {

@Override
public Bar convert(Foo convertable) {
return new Bar("This bar's converted from an instance of Foo");
}

@Override
public Bar convert(FooChild1 convertable) {
return new Bar("This bar's converted from an instance of FooChild1");
}

@Override
public Bar convert(FooChild2 convertable) {
return new Bar("This bar's converted from an instance of FooChild2");
}
}

public class Foo2BazConverter implements FooConverter {

@Override
public Baz convert(Foo convertable) {
return new Baz("This baz's converted from an instance of Foo");
}

@Override
public Baz convert(FooChild1 convertable) {
return new Baz("This baz's converted from an instance of FooChild1");
}

@Override
public Baz convert(FooChild2 convertable) {
return new Baz("This baz's converted from an instance of FooChild2");
}
}

public class Foo implements Convertable<FooConverter, Foo> {

@Override
public <R> R convertWith(FooConverter converter) {
return converter.convert(this);
}
}

public class FooChild1 extends Foo {

@Override
public <R> R convertWith(FooConverter converter) {
return converter.convert(this);
}
}

public class FooChild2 extends Foo {

@Override
public <R> R convertWith(FooConverter converter) {
return converter.convert(this);
}
}


测试代码

Foo fooObj = new Foo();
Foo fooChild1Obj = new FooChild1();
Foo fooChild2Obj = new FooChild2();

// converting to bar
Foo2BarConverter foo2BarConverter = new Foo2BarConverter();
System.out.println(fooObj.<Bar>convertWith(foo2BarConverter).getMessage());
System.out.println(fooChild1Obj.<Bar>convertWith(foo2BarConverter).getMessage());
System.out.println(fooChild2Obj.<Bar>convertWith(foo2BarConverter).getMessage());

System.out.println();

// converting to baz
Foo2BazConverter foo2BazConverter = new Foo2BazConverter();
System.out.println(fooObj.<Baz>convertWith(foo2BazConverter).getMessage());
System.out.println(fooChild1Obj.<Baz>convertWith(foo2BazConverter).getMessage());
System.out.println(fooChild2Obj.<Baz>convertWith(foo2BazConverter).getMessage());


它的输出

This bar's converted from an instance of Foo
This bar's converted from an instance of FooChild1
This bar's converted from an instance of FooChild2

This baz's converted from an instance of Foo
This baz's converted from an instance of FooChild1
This baz's converted from an instance of FooChild2


乍一看看起来很棒。但实际上,此解决方案不是类型安全的。例如以下电话

fooObj.<Baz>convertWith(foo2BarConverter).getMessage()


不会导致编译时错误。但这会在运行时导致ClassCastException。

因此,一般性问题如下。

有没有办法用Java制作无状态的泛型Typesafe Visitor?

UPD:我添加了指向所有三个实现的来源的链接: 1st2nd3rd

最佳答案

您的转换器只是简单的函数,您可能不需要“框架”来构成它们。而且您的第三次尝试没有太大意义:

<R> R convertWith(V converter);


意思是:“给一些东西(对您想要的R一无所知的V转换器),给我任何东西(任意R)”。如您所知,这是行不通的。

使用 corrected visitor pattern的简单实现:

interface FooConverter<R> extends Function<Foo, R> {

R convert(Foo convertable);

R convert(FooChild1 convertable);

R convert(FooChild2 convertable);

default R apply(Foo foo) { return foo.convertWith(this); }
}

public class Foo2BarConverter implements FooConverter<Bar> {

@Override
public Bar convert(Foo convertable) {
return new Bar("This bar's converted from an instance of Foo");
}

@Override
public Bar convert(FooChild1 convertable) {
return new Bar("This bar's converted from an instance of FooChild1");
}

@Override
public Bar convert(FooChild2 convertable) {
return new Bar("This bar's converted from an instance of FooChild2");
}
}

public class Foo2BazConverter implements FooConverter<Baz> {

@Override
public Baz convert(Foo convertable) {
return new Baz("This baz's converted from an instance of Foo");
}

@Override
public Baz convert(FooChild1 convertable) {
return new Baz("This baz's converted from an instance of FooChild1");
}

@Override
public Baz convert(FooChild2 convertable) {
return new Baz("This baz's converted from an instance of FooChild2");
}
}

public class Foo{

public <R> R convertWith(FooConverter<R> converter) {
return converter.convert(this);
}
}

public class FooChild1 extends Foo {

@Override
public <R> R convertWith(FooConverter<R> converter) {
return converter.convert(this);
}
}

public class FooChild2 extends Foo {

@Override
public <R> R convertWith(FooConverter<R> converter) {
return converter.convert(this);
}
}

public void test() {
Foo fooObj = new Foo();
Foo fooChild1Obj = new FooChild1();
Foo fooChild2Obj = new FooChild2();

// converting to bar
Foo2BarConverter foo2BarConverter = new Foo2BarConverter();
System.out.println(fooObj.convertWith(foo2BarConverter).getMessage());
System.out.println(fooChild1Obj.convertWith(foo2BarConverter).getMessage());
System.out.println(fooChild2Obj.convertWith(foo2BarConverter).getMessage());

System.out.println();

// converting to baz
Foo2BazConverter foo2BazConverter = new Foo2BazConverter();
System.out.println(fooObj.convertWith(foo2BazConverter).getMessage());
System.out.println(fooChild1Obj.convertWith(foo2BazConverter).getMessage());
System.out.println(fooChild2Obj.convertWith(foo2BazConverter).getMessage());

// does not compile:
fooObj.<Baz>convertWith(foo2BarConverter).getMessage();
}


然后,如果您需要更多框架,则可能需要研究一下镜头: https://github.com/functionaljava/functionaljava/tree/master/core/src/main/java/fj/data/optic

关于java - Java中访客模式的通用实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36363142/

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