- List<? extends Fruit> arguments;
现在,我想调用这些对象的方法.调用类有一个方法来清洗每个扩展Fruit的类,但不适用于Fruit抽象类:
- void wash( Apple a);
- void wash( Peach p);
如何将方法清理应用于参数中的所有元素?这不工作,因为我的洗涤方法不接受水果参数:
- for( Fruit f: arguments)
- this.wash( f); // the wash() method is not a member of Fruit
有没有什么办法可以解决这个问题,而不用做伞法洗(水果)?因为有数十种洗涤(?延伸水果)方法…
.
编辑:我正在谈论的“引用班”是访客.我不能改变任何Fruit类/子类.我只能为访客编程这意味着不可能将abstract()方法(或任何其他方法)添加到抽象类Fruit中.
解决方法
AFAIK,你不能轻松地在Java上做.你可以做两种方式:quick’n’dirty,和访客方式:
Quick’n’dirty
您需要询问对象的类型,因此您需要在Fruit上使用一种清洗方法,该方法将根据其类型将调用重定向到正确的功能:
- public void wash(Fruit f)
- {
- if(f instanceof Apple)
- {
- wash((Apple) f) ;
- }
- else if(f instanceof Peach)
- {
- wash((Peach) f) ;
- }
- else
- {
- // handle the error,usually through an exception
- }
- }
quick’n’dirty的问题是,编译器不会告诉你,目前没有洗涤方法处理的新的有效的Fruit(例如Orange).
游客
您可以使用访客模式进行结果:
- public abstract class Fruit
- {
- // etc.
- public abstract void accept(FruitVisitor v) ;
- }
- public class Apple extends Fruit
- {
- // etc.
- public void accept(FruitVisitor v)
- {
- v.visit(this) ;
- }
- }
- public class Peach extends Fruit
- {
- // etc.
- public void accept(FruitVisitor v)
- {
- v.visit(this) ;
- }
- }
并将访问者定义为:
- public interface class FruitVisitor
- {
- // etc.
- // Note that there are no visit method for Fruit
- // this is not an error
- public void visit(Apple a) ;
- public void visit(Peach p) ;
- }
然后,您的洗衣机的访客:
- public class FruitVisitorWasher : implements FruitVisitor
- {
- // etc.
- // Note that there are no visit method for Fruit
- // this is not an error
- // Note,too,that you must provide a wash method in
- // FruitVisitorWasher (or use an anonymous class,as
- // in the example of the second edit to access the
- // wash method of the outer class)
- public void visit(Apple a)
- {
- wash(a) ;
- }
- public void visit(Peach p)
- {
- wash(p) ;
- }
- }
最后,你的代码可能是
- FruitVisitorWasher fvw = new FruitVisitorWasher() ;
- for( Fruit f: arguments)
- {
- f.accept(fvw) ;
- }
Etvoilà…
访问者模式具有编译器会告诉您如果您添加了另一个水果(例如橙色)的优势,其中您编码了接受方法,并且忘记更新FruitVisitor模式以支持它.
然后,访客模式是可扩展的:您可以拥有一个FruitVisitorWasher,一个FruitVisitorEater,一个FruitVisitorWhatever,添加它们,而不需要修改Fruit,Apple,Peach等.
一个陷阱,但是,您必须手动写入每个Fruit类的accept方法(这是一个复制/粘贴操作),因为它是所有的工作“知道”正确的水果类型的方法.
编辑
如果你去找Quick’n’dirty解决方案,Samuel Parsonage的解决方案可能比我的更好:
How to iterate over this generic List with wildcards?
这使得Java的反思(我是一个C编码器,所以反射不会成为一个自然的解决方案…我的坏…).我发现他的解决方案非常优雅,即使它闻到某种东西(所有的检查都将在运行时完成,所以你最好确保一切都OK …再次,通过C背景:如果有事情可以完成或错误可以在编译时检测到,在运行时移动应该尽可能避免)
编辑2
约翰·亚施普托特(John Assymptoth)评论说:
The Visitor pattern as you write it isn’t an option,since I can’t add the method wash to Fruit.
所以我会提供内联代码来证明wash()不会在Fruit里面工作.
(我将FruitVisitor从抽象类改为界面,这更好)
让我们想象一下,for循环在Foo类的bar方法里面,它有自己的洗涤方法:
- public class Foo
- {
- public wash(Apple a) { /* etc. */ }
- public wash(Peach p) { /* etc. */ }
- public bar(List<? extends Fruit> arguments)
- {
- for( Fruit f: arguments)
- {
- wash(f) ; // we wand the right wash method called.
- }
- }
- }
让我们重新使用FruitVisitor模式来纠正这个代码.我们将在bar方法中使用一个匿名类:
- public class Foo
- {
- public void wash(Apple a) { System.out.println("Apple") ; }
- public void wash(Peach p) { System.out.println("Peach") ; }
- public void bar(List<? extends Fruit> arguments)
- {
- FruitVisitor fv = new FruitVisitor()
- {
- public void visit(Apple a)
- {
- wash(a) ; // will call the wash method
- // of the outer class (Foo)
- }
- public void visit(Peach p)
- {
- wash(p) ; // will call the wash method
- // of the outer class (Foo)
- }
- } ;
- for(Fruit f: arguments)
- {
- f.accept(fv) ;
- }
- }
- }
现在,它的作品,水果中没有洗涤方法.