Философия Java3
Шрифт:
//. typeinfo/SimpleProxyDemo java import static net mindview.util Print *,
interface Interface { void doSomethingO; void somethingElse(String arg).
}
class Real Object implements Interface {
public void doSomethingO { printC'doSomething"); } public void somethingElse(String arg) { printC'somethingElse " + arg),
}
}
class SimpleProxy implements Interface { private Interface proxied, public SimpleProxy(Interface proxied) { this.proxied = proxied,
}
public void doSomethingO {
print("SimpleProxy doSomething"), proxied doSomethingO,
}
public void somethingElse(String arg) {
print("SimpleProxy somethingElse " + arg); proxied.somethingElse(arg);
}
class SimpleProxyDemo {
public static void consumer^Interface iface) { iface doSomethingO; iface somethingElseC'bonobo");
}
public static void main(String[] args) { consumer(new RealObjectO), consumer(new SimpleProxy(new RealObjectO)),
}
} /* Output doSomething somethingElse bonobo SimpleProxy doSomething doSomething
SimpleProxy somethingElse bonobo
somethingElse bonobo */// ~
Поскольку consumer
Посредник пригодится в любой ситуации, когда требуется отделить дополнительные операции от «настоящего» объекта, и особенно когда нужно легко переключаться из режима использования дополнительных операций в режим отказа от них (и наоборот — главной целью паттернов является инкапсуляция изменений, поэтому для оправдания их применения что-то должно изменяться). Допустим, вы хотите отслеживать вызовы методов 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);
//
}
} /* 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.