Чтение онлайн

ЖАНРЫ

Философия Java3

Эккель Брюс

Шрифт:

Приведенный выше результат был получен из командной строки

java ShowMethods ShowMethods

На экран выводится открытый (public) конструктор по умолчанию, хотя в тексте программы такой конструктор не определяется. Тот конструктор, что имеется теперь в классе, автоматически сгенерирован компилятором. Если вы после этого сделаете класс ShowMethods не открытым (удалите из его определения спецификатор доступа public, то есть предоставите ему доступ в пределах пакета), сгенерированный компилятором конструктор исчезнет из списка методов. Сгенерированный конструктор имеет тот же уровень доступа, что и его класс.

Также интересно

запустить программу в виде

java ShowMethods java lang String

с передачей дополнительного параметра char, int, String и т. п.

Эта программа сэкономит вам немало времени при программировании, когда вы будете мучительно вспоминать, есть ли у этого класса определенный метод, если вам потребуется узнать, имеются ли у некоторого класса методы, возвращающие объекты Color, и т. д.

Динамические посредники

«Посредник» (proxy) принадлежит к числу основных паттернов проектирования. Он представляет собой объект, который подставляется на место «настоящего» объекта для расширения или модификации его операций. Приведу тривиальный пример, показывающий структуру посредника:

//. 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 получает 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);

Поделиться с друзьями: