2010-06-14 1 views
0

Я имел дело с hibernate, пытаясь выяснить класс времени выполнения за прокси-серверами, используя шаблон посетителя. Затем я придумал подход AbstractVisitable, но мне интересно, будет ли он всегда давать правильные результаты.Java абстрактный посетитель - гарантированный успех? Если да, то почему?

Рассмотрим следующий код:

interface Visitable { 
    public void accept(Visitor v); 
} 

interface Visitor { 
    public void visit(Visitable visitorHost); 
} 

abstract class AbstractVisitable implements Visitable { 
    @Override 
    public void accept(Visitor v) { 
     v.visit(this); 
    } 
} 

class ConcreteVisitable extends AbstractVisitable { 
    public static void main(String[] args) { 
     final Visitable visitable = new ConcreteVisitable(); 
     final Visitable proxyVisitable = (Visitable) Proxy.newProxyInstance(
       Thread.currentThread().getContextClassLoader(), 
       new Class<?>[] { Visitable.class }, new InvocationHandler() { 
        @Override 
        public Object invoke(Object proxy, Method method, 
          Object[] args) throws Throwable { 
         return method.invoke(visitable, args); 
        } 
       }); 
     proxyVisitable.accept(new Visitor() { 
      @Override 
      public void visit(Visitable visitorHost) { 
       System.out.println(visitorHost.getClass()); 
      } 
     }); 
    } 
} 

Это делает ConcreteVisitable, который наследует accept метод от AbstractVisitable. В C++ я бы счел это рискованным, поскольку в AbstractVisitable может ссылаться на AbstractVisitable::this, а не ConcreteVisitable::this. Я был обеспокоен тем, что код при определенных обстоятельствах будет печатать class AbstractVisible. Однако код выше выводит class ConcreteVisitable, хотя я скрыл реальный тип за динамическим прокси (самый сложный случай, который я мог бы придумать). Является ли подход абстрактного посетителя выше гарантированного, чтобы работать, или есть некоторые подводные камни с этим подходом?

Какие гарантии даны в Java относительно указателя this?

ответ

2

this всегда указывает на этот объект, как вы могли догадаться. Какой тип в иерархии, из которой вы его используете, не имеет значения, если вы не используете его для ссылки на не виртуальные вещи (например, частные поля/методы или не дай бог, статические методы). getClass() является виртуальным.

Теперь я ожидаю, что вы сбиваете с толку поведение this для того, чтобы думать, что Java имеет множественную отправку. Это не так. Если вы меняете посетитель этого:

class Visitor { 
    public void visit(Visitable visitorHost); 
    public void visit(ConcreteVisitable visitorHost); 
} 

А потом реализовать это следующим образом:

public void visit(Visitable visitorHost) { 
    System.out.println("Visitable"); 
} 
public void visit(ConcreteVisitable visitorHost) { 
    System.out.println("ConcreteVisitable"); 
} 

Было бы действительно печатать «Visitable», а не «ConcreteVisitable», так как Java не выполняет double dispatch.

+0

Приятный завершающий «getClass() является виртуальным» был ключевым фактом, который я наблюдал. –

0

Ваш динамический прокси-сервер передает вызов accept (...) в базовый Visitable, который затем вызывает visit (...), передавая себя в качестве аргумента. Прокси никогда не участвует ни в чем, кроме прохождения через вызов accept(), поэтому к моменту, когда он попадает в реализацию метода посещения (...), Visitable рассматривается как конкретный экземпляр, лишенный прокси-сервера.

 Смежные вопросы

  • Нет связанных вопросов^_^