Эккель Брюс
Шрифт:
}
} /* Output doSomething somethingElse bonobo SimpleProxy doSomething doSomething
SimpleProxy somethingElse bonobo
somethingElse bonobo */// ~
Поскольку consumer получает Interface, он не знает, что ему передается — «настоящий» объект (RealObject) или посредник (Proxy), потому что оба типа реализуют Interface. Объект Proxy, находящийся между клиентом и «настоящим» объектом, выполняет операции, а затем вызывает идентичные методы RealObject.
Посредник пригодится в любой ситуации, когда требуется отделить дополнительные операции от «настоящего» объекта, и особенно когда нужно легко переключаться из режима использования дополнительных операций в режим отказа от них (и наоборот — главной целью паттернов является инкапсуляция изменений, поэтому для оправдания их применения что-то должно изменяться). Допустим, вы хотите отслеживать вызовы методов RealObject, измерять затраты на эти вызовы, и т. д. Такой код не должен встраиваться в приложение, а посредник позволит легко добавить или убрать его по мере необходимости.
Динамические посредники Java развивают концепцию посредника — и объект посредника создается динамически, и обработка вызовов опосредованных методов тоже осуществляется динамически. Все вызовы, обращенные к динамическому посреднику, перенаправляются одному обработчику, который определяет, что это за вызов и как с ним следует поступить. Вот как выглядит пример SimpleProxyDemo.java, переписанный для динамического посредника:
// typeinfo/SimpleDynamicProxy java import java lang.reflect *.
class DynamicProxyHandler implements InvocationHandler { private Object proxied; public DynamicProxyHandler(Object proxied) { this proxied = proxied,
}
public Object
invoke(Object proxy, Method method, Object[] args) throws Throwable {
System out.printlnC'**** proxy. " + proxy.getClass +
method- " + method + ", args " + args); if(args != nul 1) продолжение &
for(Object arg : args)
System.out.println(" " + arg); return method.invoke(proxied, args);
}
}
class SimpleDynamicProxy {
public static void consumer(Interface iface) { iface.doSomething; i face.somethi ngElse("bonobo");
}
public static void main(String[] args) {
Real Object real = new Real ObjectО; consumer(real);
// Вставляем посредника и вызываем снова: Interface proxy = (Interface)Proxy.newProxyInstance( Interface.class.getClassLoader, new Class[]{ Interface.class }. new DynamicProxyHandler(real)); consumer(proxy);
}
} /* Output. doSomething somethingElse bonobo
**** proxy: class SProxyO. method: public abstract void Interface.doSomething, args: null
doSomething
**** proxy: class SProxyO. method: public abstract void
Interface.somethi ngElse(java.1ang.Stri ng), args: [Ljava.1ang.Object.@42e816
bonobo somethingElse bonobo *///:-
Динамический посредник создается вызовом статического метода Proxy. newProxyInstance, которому должен передаваться загрузчик класса, список интерфейсов, которые должны реализовываться посредником (а не классов или абстрактных классов!), а также реализация интерфейса Invocation Handler. Динамический посредник перенаправляет все вызовы обработчику, поэтому конструктор обработчика обычно получает ссылку на «настоящий» объект для перенаправления ему запросов.
Метод invoke получает объект посредника на случай, если ему понадобится определить, откуда поступил запрос — впрочем, обычно это несущественно. Будьте внимательны при вызове методов посредника из invoke, потому что вызовы через интерфейс перенаправляются через посредника.
В общем случае вы выполняете опосредованную операцию, а затем используете Method.invoke для перенаправления запроса опосредованному объекту с передачей необходимых аргументов. При этом некоторые вызовы методов могут отфильтровываться, а другие — проходить:
//: typeinfo/SelectingMethods.java
// Looking for particular methods in a dynamic proxy.
import java.lang.reflect.*;
import static net.mindview.util.Print.*;
class MethodSelector implements InvocationHandler {
private Object proxied; public MethodSelector(Object proxied) { this proxied = proxied;
}
public Object
invoke(Object proxy, Method method. Objectd args) throws Throwable {
i f(method.getName.equals("i nteresti ng"))
print("Посредник обнаружил интересный метод"); return method.invoke(proxied. args);
}
}
interface SomeMethods { void boringlO; void boring2; void interesting(String arg). void boring3;
}
class Implementation implements SomeMethods { public void boringlO { printC'boringl"); } public void boring2 { print("boring2"); } public void interesting(String arg) { print("interesting " + arg);
}
public void boring3 { print("boring3"); }
}
class SelectingMethods {
public static void main(String[] args) {
SomeMethods proxy= (SomeMethods)Proxy.newProxyInstance( SomeMethods.class.getClassLoader.