访问者模式在Java中的通用实现

访问者模式在Java中的通用实现,java,generics,design-patterns,visitor-pattern,Java,Generics,Design Patterns,Visitor Pattern,我做了一些研究,试图开发一个类型转换框架,它提供了将源类(例如Foo)的实例转换为结果类(例如Bar或Baz)实例的能力。该框架应该能够为同一对源和结果使用不同的转换逻辑(即不同的转换器)。它还应该是可扩展的,即允许为新的和现有的源和结果对添加新的转换器。还有一个要求是类型安全性,即,任何试图将某个源类的实例转换为结果类的实例而未实现适当转换逻辑的转换程序都会导致编译时错误 我决定使用一个以转换器为访问者,以可转换类为元素的。为了提供可扩展性和类型安全性,我决定使用泛型。因此,我所做的转换框架的

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

我决定使用一个以转换器为访问者,以可转换类为元素的。为了提供可扩展性和类型安全性,我决定使用泛型。因此,我所做的转换框架的第一个实现受到互联网上某些文章的影响(不幸的是,我失去了链接),是

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

以下是框架、转换器和可转换文件的核心接口:

    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);
    }
下面是一些可以使用该转换器转换的类:

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);
    }
}
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());
下面是一个测试转换器的代码:

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);
    }
}
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());
和由该代码生成的输出

此栏是从Foo实例转换而来的
此栏是从FooChild1的实例转换而来的
此栏是从FooChild2的实例转换而来的
这个baz是从Foo的一个实例转换而来的
这个baz是从FooChild1的实例转换而来的
这个baz是从FooChild2的实例转换而来的
查看
Foo2BazConverter
Foo2BazConverter
中的
result
字段。这是实现的主要缺点。它使转换器充满状态,这并不总是方便的。为了避免我的缺点

无双重分派的转换框架

此实现的要点是使用结果类参数化转换器,并从
convert
方法的
convert
convertWith
方法的
Convertable
返回结果。下面是它在代码中的外观:

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);
    }
}
以及它的输出,这表明在这个实现中不调用重写方法

此栏是从Foo实例转换而来的
此栏是从Foo实例转换而来的
此栏是从Foo实例转换而来的
这个baz是从Foo的一个实例转换而来的
这个baz是从Foo的一个实例转换而来的
这个baz是从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);
    }
}
乍一看很不错。但事实上,这个解决方案不是类型安全的。例如,下面的调用

fooObj.<Baz>convertWith(foo2BarConverter).getMessage()
fooObj.convertWith(foo2BarConverter.getMessage())
不会导致编译时错误。但它会在运行时导致ClassCastException

因此,一般问题如下

有没有一种方法可以使用Java创建无状态泛化类型安全访问者?


UPD:我已经添加了指向所有三种实现的源代码的链接:

您的转换器只是函数,您可能不需要“框架”来组合它们。你的第三次尝试没有多大意义:

<R> R convertWith(V converter);
R转换器与(V转换器);
意思是:“给定一些东西(V转换器对你想要的R一无所知),给我任何东西(任意的R)”。你发现这不管用

使用以下命令的简单实现:

接口FooConverter扩展函数{ R转换(Foo可转换); R转换(FooChild1可转换); R转换(FooChild2可转换); 默认R应用(Foo Foo){return Foo.convertWith(this);} } 公共类Foo2BarConverter实现FooConverter{ @凌驾 公共酒吧转换(Foo可转换){ 返回新条(“此条是从Foo实例转换而来的”); } @凌驾 公共栏转换(FooChild1可转换){ 返回新条(“此条从FooChild1实例转换而来”); } @凌驾 公共酒吧转换(FooChild2可转换){ 返回新条(“此条是从FooChild2实例转换而来的”); } } 公共类Foo2BazConverter实现FooConverter{ @凌驾 公共Baz转换(Foo可转换){ 返回新的Baz(“此Baz是从Foo实例转换而来的”); } @凌驾 公共Baz转换(FooChild1可转换){ 返回新的Baz(“此Baz是从FooChild1实例转换而来的”); } @凌驾 公共Baz转换(FooChild2可转换){ 返回新的Baz(“此Baz是从FooChild2实例转换而来的”); } } 公开课Foo{ 带(FooConverter)的公共R转换器{ 返回转换器。转换(此); } } 公共类FooChild1扩展了Foo{ @凌驾 带(FooConverter)的公共R转换器{ 返回转换器。转换(此); } } 公共类FooChild2扩展了Foo{ @凌驾 带(FooConverter)的公共R转换器{ 返回转换器。转换(此); } } 公开无效测试(){ Foo fooObj=新的Foo(); Foo fooChild1Obj=新的FooChild1(); Foo fooChild2Obj=新的FooChild2(); //转换为酒吧 Foo2BarConverter Foo2BarConverter=新的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(); //转换为baz Foo2BazConverter Foo2BazConverter=新的Foo2BazConverter(); System.out.println(fooObj.convertWith(foo2BazConverter.getMessage())
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();
}
public class ParentDataModel
{
    public void accept(Visitor visitor)
    {
        visitor.visit(this);
    }
}

public class ChildDataModel extends ParentDataModel
{
    // no need to implement accept() by the child itself
}

public class Visitor
{
    public void visit(ParentDataModel model)
    {
        // do something with it
    }

    public void visit(ChildDataModel model)
    {
        // do something with it
    }
}
public class NumberWrapper
{
    private Number value;

    public void accept(Visitor visitor)
    {
        visitor.visit(value);
    }
}

public class DoubleWrapper
{
    private Double value;

    public void accept(Visitor visitor)
    {
        visitor.visit(value);
    }
}

public class Visitor
{
    public void visit(Number value)
    {
        // do something with it
    }

    public void visit(Double value)
    {
        // do something with it
    }
}
public static class SuperConsumer implements Consumer
{
    private Map<Class<?>, Consumer<?>> consumers = new HashMap<>();
    private Consumer<?> unknown = o -> System.err.println("Unknown object type");

    public SuperConsumer()
    {
        consumers.put(Number.class, o -> consumeNumber(o));
        consumers.put(Double.class, o -> consumeDouble(o));
    }

    private void consumeNumber(Number value)
    {
         System.out.printf("Consuming: %s\n", value.getClass().getName());
    }

    private void consumeDouble(Double value)
    {
         System.out.printf("Consuming: %s\n", value.getClass().getName());
    }

    private Consumer findConsumer(Object object)
    {
        Consumer consumer = consumers.get(object.getClass());

        Class superClazz = object.getClass().getSuperclass();
        while (consumer == null && superClazz != Object.class)
        {
            consumer = consumers.get(superClazz);
            superClazz = superClazz.getSuperclass();
        }

        Class<?>[] interfaces = object.getClass().getInterfaces();
        for (int i = 0; consumer == null && i < interfaces.length; i++)
        {
            consumer = consumers.get(interfaces[i]);
        }

        return consumer;
    }

    @Override
    public void accept(Object object)
    {
        Consumer consumer = findConsumer(object);
        if (consumer == null)
        {
            consumer = unknown;
        }
        consumer.accept(object);
    }

    public static void main(String[] args)
    {
        Consumer consumer = new SuperConsumer();
        Arrays.asList(new Double(1.0), new Integer(1), new Float(1.0f)).forEach(o -> consumer.accept(o));
    }
}