在Java中实现Visitor模式 [英] Generified implementation of Visitor pattern in Java
问题描述
我决定使用访问者模式,转换器作为访问者和可转换类作为元素。为了提供可扩展性和类型安全性,我决定使用泛型。所以我所做的转换框架的第一次实现受到互联网上的一些文章的影响(不幸的是我失去了链接)是...
转换框架与statefull转换器
以下是框架的核心界面,转换器和可转换:
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);
}
泛型使可转换
只接受 Converter
的实现,可以转换它们并实现 Converter
只访问 Convertable
它是为了转换。以下是这样的转换器的示例:
interface FooConverter扩展Converter&FooConverter,Foo> {
void convert(Foo convertable);
void convert(FooChild1 convertable);
void convert(FooChild2 convertable);
}
public class Foo2BarConverter实现FooConverter {
private Bar result;
public Bar getResult(){
return result;
}
@Override
public void convert(Foo convertable){
this.result = new Bar(此条从Foo的实例转换);
}
@Override
public void convert(FooChild1 convertable){
this.result = new Bar(此条从FooChild1的一个实例转换);
}
@Override
public void convert(FooChild2 convertable){
this.result = new Bar(此条从FooChild2的实例转换);
}
}
public class Foo2BazConverter实现FooConverter {
私人Baz结果;
public Baz getResult(){
return result;
}
@Override
public void convert(Foo convertable){
this.result = new Baz(这个baz从Foo的一个实例转换);
}
@Override
public void convert(FooChild1 convertable){
this.result = new Baz(这个baz从FooChild1的一个实例转换);
}
@Override
public void convert(FooChild2 convertable){
this.result = new Baz(这个baz从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);
}
}
这里是结果类,即 Bar
和 Baz
:
public class Bar {
private String message;
公共栏(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;
}
}
这里是一个测试转换器的代码: / p>
Foo fooObj = new Foo();
Foo fooChild1Obj = new FooChild1();
Foo fooChild2Obj = new FooChild2();
//转换为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());
//转换为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
/ pre>
的实例转换此条从FooChild1的实例转换
此条从FooChild2 $ b的实例转换
$ b这个baz从Foo
的一个实例转换这个baz从FooChild1的一个实例转换为
这个baz从一个FooChild2的实例转换
查看
中的
和结果
字段Foo2BarConverterFoo2BazConverter
。这是实现的主要缺点。这使得转换器状态不总是方便。试图避免这个缺点我开发了...
没有双重调度的转换框架
这个实现的要点是参数化转换器,其结果类和返回结果来自
convert
方法Converter
和convertWith
方法可转换
。以下是代码中的代码: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>转换器);
}
public interface FooConverter< R>扩展转换器< 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(此条从Foo的实例转换);
}
@Override
public Bar convert(FooChild1 convertable){
return new Bar(此条从FooChild1的一个实例转换);
}
@Override
public Bar convert(FooChild2 convertable){
return new Bar(此条从FooChild2的实例转换);
}
}
public class Foo2BazConverter实现FooConverter< Baz> {
@Override
public Baz convert(Foo convertable){
return new Baz(这个baz从Foo的一个实例转换);
}
@Override
public Baz convert(FooChild1 convertable){
return new Baz(这个baz从FooChild1的一个实例转换);
}
@Override
public Baz convert(FooChild2 convertable){
return new Baz(这个baz从FooChild2的一个实例转换);
}
}
public class Foo implements Convertable< Foo> {
@Override
public< R> R convertWith(Converter< Foo,R>转换器){
return converter.convert(this);
}
}
public class FooChild1 extends Foo {
@Override
public< R> R convertWith(Converter< Foo,R>转换器){
return converter.convert(this);
}
}
public class FooChild2 extends Foo {
@Override
public< R> R convertWith(Converter< Foo,R>转换器){
return converter.convert(this);
}
}
V
从Convertable
声明中删除,因为在Converter
声明中的结果类将使我们实际上参数化实现的可转换
与结果类。它会将可转换的每个实现绑定到唯一可以转换为的结果类。所以convertWith
inConvertable
指接收的转换器与转换器< A,R>
界面。这就是问题。现在执行Convertable
调用收到的转换器将会调用convert
,它在Converter
接口,而不是
convert
方法,它在转换器
实现中覆盖它。换句话说,convert(FooChild1 convertable)
和convert(FooChild2 convertable)
在Foo2BarConverter
和
Foo2BazConverter
永远不会被调用。基本上,它杀死了访客模式的主要概念,双重调度。这是一个测试代码...Foo fooObj = new Foo();
Foo fooChild1Obj = new FooChild1();
Foo fooChild2Obj = new FooChild2();
//转换为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();
//转换为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());
及其输出,表明在此实现中未调用重写方法。
此条从Foo
的实例转换此条从Foo
的实例转换这个酒吧从Foo
的一个实例转换这个baz从Foo
的一个实例转换这个baz从Foo
的一个实例转换这个baz从Foo $ b的一个实例转换$ b下一个实现我试图使无状态转换器是...
具有参数化方法的转换器
这里的主要概念是仅参数化方法,我想在没有参数的情况下返回转换结果
public interface Converter< V extends Converter< V,A>,A extends Convertable< V,A>> ; {
< R> R转换(A转换);
}
public interface Convertable< V extends Converter< V,A>,A extends Convertable< V,A> {
< R> R转换(V转换器);
}
接口FooConverter扩展Converter&FooConverter,Foo> {
< R> R转换(Foo可转换);
< R> R转换(FooChild1可转换);
< R> R转换(FooChild2可转换);
}
public class Foo2BarConverter实现FooConverter {
@Override
public Bar convert(Foo convertable){
return new Bar(这个酒吧从Foo的一个实例转换成);
}
@Override
public Bar convert(FooChild1 convertable){
return new Bar(此条从FooChild1的一个实例转换);
}
@Override
public Bar convert(FooChild2 convertable){
return new Bar(此条从FooChild2的实例转换);
}
}
public class Foo2BazConverter实现FooConverter {
@Override
public Baz convert(Foo convertable){
返回新的Baz(这个baz从Foo的一个实例转换);
}
@Override
public Baz convert(FooChild1 convertable){
return new Baz(这个baz从FooChild1的一个实例转换);
}
@Override
public Baz convert(FooChild2 convertable){
return new Baz(这个baz从FooChild2的一个实例转换);
}
}
public class Foo实现Convertable&FooConverter,Foo> {
@Override
public< R> R convertWith(FooConverter转换器){
return converter.convert(this);
}
}
public class FooChild1 extends Foo {
@Override
public< R> R convertWith(FooConverter转换器){
return converter.convert(this);
}
}
public class FooChild2 extends Foo {
@Override
public< R> R convertWith(FooConverter转换器){
return converter.convert(this);
}
}
测试代码
Foo fooObj = new Foo();
Foo fooChild1Obj = new FooChild1();
Foo fooChild2Obj = new FooChild2();
//转换为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();
//转换为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());
并输出
此条从Foo
的实例转换此条从FooChild1的实例转换为
此条从FooChild2的实例转换为
这个baz从Foo
的一个实例转换这个baz从FooChild1的一个实例转换成
这个baz从FooChild2的一个实例转换成
乍看起来看起来不错。但实际上这个解决方案并不是安全的。例如以下调用
fooObj。< Baz> convertWith(foo2BarConverter).getMessage()
不会导致编译时错误。但是在运行时会导致ClassCastException。
所以一般问题如下。
有没有办法使Java成为无状态的安全访问者?
解决方案你的转换器是简单的函数,你可能不需要一个框架来组成它们。而你的第三次尝试没有什么意义:
< R> R转换(V转换器);意思是:给出一些东西(V转换器,你不需要知道R的任何东西),给我任意(任意R)。你发现这不行。
使用更正的访问者模式:
界面FooConverter< 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(此条从Foo的实例转换);
}
@Override
public Bar convert(FooChild1 convertable){
return new Bar(此条从FooChild1的一个实例转换);
}
@Override
public Bar convert(FooChild2 convertable){
return new Bar(此条从FooChild2的一个实例转换);
}
}
public class Foo2BazConverter实现FooConverter< Baz> {
@Override
public Baz convert(Foo convertable){
return new Baz(这个baz从Foo的一个实例转换);
}
@Override
public Baz convert(FooChild1 convertable){
return new Baz(这个baz从FooChild1的一个实例转换);
}
@Override
public Baz convert(FooChild2 convertable){
return new Baz(这个baz从FooChild2的一个实例转换);
}
}
public class Foo {
public< R> R convertWith(FooConverter R转换器){
return converter.convert(this);
}
}
public class FooChild1 extends Foo {
@Override
public< R> R convertWith(FooConverter R转换器){
return converter.convert(this);
}
}
public class FooChild2 extends Foo {
@Override
public< R> R convertWith(FooConverter R转换器){
return converter.convert(this);
}
}
public void test(){
Foo fooObj = new Foo();
Foo fooChild1Obj = new FooChild1();
Foo fooChild2Obj = new FooChild2();
//转换为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();
//转换为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());
//不编译:
fooObj。< Baz> convertWith(foo2BarConverter).getMessage();
}
然后如果你想要一些更多的框架,你可能想要研究镜头: https://github.com/functionaljava / functionaljava / tree / master / core / src / main / java / fj / data / optic
I've made some research trying to develop a type conversion framework which provides an ability to convert instances of a source class (e.g., Foo) to instances of result classes (e.g., Bar or Baz). The framework should provide an ability to use different conversion logic (i.e., different converters) for the same pair of a source and result. It also should be extendable, i.e. allow of adding new converters for new and existing pairs of a source and result. One more requirement is typesafety, i.e. any attempt to convert an instance of some source class to an instance of a result class without converter implementing appropriate conversion logic should lead to compile time error.
I decided to use a Visitor pattern with converters as Visitors and convertable classes as Elements. To provide extendability and typesafety I decided to use generics. So the first implementation of the conversion framework I made being influenced by some article in the Internet (unfortunately I've lost the link) was...
Conversion framework with statefull converters
Here are the core interfaces of the framework, Converter and 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); }
Generics make an implementation of
Convertable
accept only implementations ofConverter
which can convert them and make an implementation ofConverter
visit only implementations ofConvertable
which it's made to convert. Here is an example of such converters: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"); } }
And here are some classes which could be converted with that converters:
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); } }
Here are result classes, i.e.
Bar
andBaz
: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; } }
And here is a code which tests that converters:
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());
and output built by this code
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
Take a look at
result
field inFoo2BarConverter
andFoo2BazConverter
. That's the main drawback of the implementation. It makes converters statefull which is not always handy. Trying to avoid this drawback I developed...Conversion framework without double dispatching
The main point of this implementation is to parametrize converters with result classes and return results from
convert
method ofConverter
andconvertWith
method ofConvertable
. Here is how it looks in code: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); } }
V
is removed fromConvertable
declaration because having a result class inConverter
declaration would have us in fact to parametrize implementations ofConvertable
with result classes. It would bound each implementation of convertable to the only result class it could be converted to. SoconvertWith
inConvertable
refers received converters withConverter<A,R>
interface. And that's the problem. Now implementations ofConvertable
invoking received converter will allways invokeconvert
which is defined inConverter
interface and notconvert
methods which override it inConverter
implementations. In other wordsconvert(FooChild1 convertable)
andconvert(FooChild2 convertable)
inFoo2BarConverter
andFoo2BazConverter
will never be called. Basically, it kills the main notion of Visitor pattern, double dispatching. Here is a test code...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());
and its output which demonstrates that overriding methods aren't called in this implementation.
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
Next implementation I tried to make stateless converters with was...
Converters with parametrized methods
The main notion here is to parametrize only methods which I want to return a conversion result without parametrizing declarations of interfaces.
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); } }
Testing code
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());
and it's output
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
At first glance looks great. But in fact this solution isn't typesafe. For example the following call
fooObj.<Baz>convertWith(foo2BarConverter).getMessage()
wouldn't cause a compile time error. But it would lead to ClassCastException in runtime.
So the general question is the following.
Is there a way to make a stateless generifyed typesafe Visitor with Java?
UPD: I've added links to sources of all three implementations: 1st, 2nd and 3rd
解决方案Your converters are simply functions, you probably do not need a "framework" to compose them. And your third try do not make much sense:
<R> R convertWith(V converter);
mean: "given something (the V converter that know nothing about the R you want), give me anything (arbitrary R)". As you found out this does not work.
Simple Implementation using the 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(); }
Then if you want some more framework, you may want to look into lenses: https://github.com/functionaljava/functionaljava/tree/master/core/src/main/java/fj/data/optic
这篇关于在Java中实现Visitor模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!