Какова реальная цель разработки прокси-класса? - PullRequest
3 голосов
/ 05 мая 2020

Я изучал прокси-классы и не совсем понимаю, как их спроектировать.

Из того, что я до сих пор узнал, это объект-оболочка, который может управлять доступом к исходному объекту. Но если мы хотим контролировать это, почему мы не можем разработать исходный класс с этими механизмами доступа.

Я читал, что эти прокси-объекты полезны для отслеживания вызовов методов, маршрутизации вызовов методов на удаленные серверы.

Но я искал вопрос, который объяснил бы мне это, в java, но не нашел.

Я проиллюстрирую код программы трассировки методов, которая была в книга, о которой я говорил.

public class ProxyTest {

  public static void main(String[] args) throws ClassNotFoundException {

     var elements = new Object[1000];

     // fill elements with proxies for the integers 1 . . . 1000
     for (int i = 0; i < elements.length; i++) {
       Integer value = i + 1;
       var handler = new TraceHandler(value);
       Object proxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Comparable.class}, handler);
       elements[i] = proxy;
     }

     // construct a random integer
     Integer key = new Random().nextInt(elements.length) + 1;

     // search for the key
     int result = Arrays.binarySearch(elements, key);

     // print match if found
     if (result >= 0)
        System.out.println(elements[result]);

  }

}

/**
 * An invocation handler that prints out the method name and parameters, then
 * invokes the original method
 **/

class TraceHandler implements InvocationHandler{

  private Object target;

  /**
   * Constructs a TraceHandler
   * @param t the implicit parameter of the method call
   **/

  public TraceHandler(Object t){
    target = t;
  }

  public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {

     // print implicit argument
     System.out.print(target);

     // print method name
     System.out.print("." + m.getName() + "(");

     // print explicit arguments
     if (args != null){
       for (int i = 0; i < args.length; i++){
         System.out.print(args[i]);
         if (i < args.length - 1)
           System.out.print(", ");
       }
     }

     System.out.println(")");

     // invoke actual method
     return m.invoke(target, args);

  }

}

Может кто-нибудь указать мне, пожалуйста, что происходит с этим шаблоном проектирования прокси, что он делает в этой конкретной программе и его преимущества?

Ответы [ 4 ]

3 голосов
/ 09 мая 2020

Прокси-классы чрезвычайно полезны, когда вы имеете дело с кодом от других команд или третьих лиц, и их можно использовать для всех видов диагностики или расширенных операций.

Я использовал их с поставщиком баз данных JDB C Банки соединений и отказоустойчивые вызовы удаленного сервера, когда прокси-сервер обрабатывает ошибки или повторные соединения, а журнал приложений c чище.

Ваш TraceHandler может быть автономным классом, добавив метод:

@SuppressWarnings("unchecked")
public static <T> T create(final T impl, final Class<?>... interfaces)
{
    final Class<?> cls = impl.getClass();

    return (T)Proxy.newProxyInstance(cls.getClassLoader(), interfaces, new TraceHandler(impl));
}

Затем вы можете использовать TraceHandler для мониторинга / регистрации ЛЮБОГО интерфейса, используемого вашим приложением:

SomeObject x = TraceHandler.create(x, SomeObject.class);
FileVisitor myvisitor = TraceHandler.create(visitor, FileVisitor.class)

Надеюсь, тогда станет яснее, чем могут быть полезны прокси-классы, и следующий пример:

public class ProxyTest
{
    public static void main(String[] args) {

        var elements = new Integer[1000];

        for (int i = 0; i < elements.length; i++) {
            elements[i] = Integer.valueOf(i);
        }

        // construct a random integer
        Integer key = new Random().nextInt(elements.length) + 1;

        Comparator<Integer> comparator = Integer::compare;
        Comparator<Integer> comparator2 = TraceHandler.create(comparator, Comparator.class);

        // search for the key
        System.out.println("Search for "+key+" without proxy:");
        int result = Arrays.binarySearch(elements, key, comparator);

        // print match if found
        if (result >= 0)
           System.out.println(elements[result]);

        System.out.println("Search "+key+" with proxy:");
        int result2 = Arrays.binarySearch(elements, key, comparator2);
        if (result2 >= 0)
            System.out.println(elements[result]);
     }
}
3 голосов
/ 10 мая 2020

Очень широкий вопрос:

вокруг этого есть несколько разных вариантов:

  • Шаблон прокси - способ манипулирования одним объектом другим мысленным взором
  • также ленивая загрузка также может быть частью этого обсуждения
  • , наконец, самый популярный - динамические c прокси и улучшение кода после компиляции. Так работают многие известные фреймворки (например, spring, hibernate, selenium). Это позволяет добиться более читаемого кода и повысить его качество (меньше ошибок). Dynami c прокси-серверы приносят динамику c возможность ленивой инициализации, улучшения кода, более декларативный код

Например, Spring транзакционная аннотация в работе

class UsersDao {
@Transactional
  public void method() {
    // DO SOME STUFF
  }
}

Spring создает динамику c прокси, который «расширяет» UsersDao, но на самом деле перенаправляет все вызовы методов на определенный c объект, реализующий интерфейс InvocationHandler

пример InvocationHandler

public interface InvocationHandler {

    /**
     * Processes a method invocation on a proxy instance and returns
     * the result.  This method will be invoked on an invocation handler
     * when a method is invoked on a proxy instance that it is
     * associated with.
     */
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

Внутри пружины «invoke» что-то вроде этого:

Transaction tx = TransactionManager.createTransaction()
try {
    // execute method
    method.invoke();
    tx.commit()

}
catch (Exception e) {
   // execute callback 
    tx.rollback()
}
finally () {
   // do clean up
   // tx.flush()
}

Это достигается с помощью магов c динамиков c прокси

инструментов для динамических c проксирования:

https://github.com/cglib/cglib/wiki

https://www.javassist.org/

https://docs.oracle.com/javase/6/docs/api/java/lang/reflect/Proxy.html

1 голос
/ 09 мая 2020

Давайте удалим весь фокус-покус номенклатур и просто поймем это в реальном мире на примере:

  1. Боб и его 10 000 друзей go смотрят футбольный матч.
  2. Из соображений безопасности охранники у входных ворот обязаны проверять билеты всех людей, а затем пропускать их.
  3. На стадионе также есть киоски с пиццей и пивом, но вы можете Покупайте их только в том случае, если у вас есть действующий билет.
  4. Теперь, поскольку мы знаем, что охранники выполняли свои обязанности, и никто без действительного билета не мог войти на стадион, продавцам пиццы и пива не нужно проверять билеты каждого человека.

А теперь давайте посмотрим-

  1. Охранники действуют как прокси-слой между стадионами и остальным миром.
  2. Если бы там не было охранников, всем продавцам пиццы и пива пришлось бы написать код проверки билетов или, по крайней мере, самому позвонить по этому фрагменту кода. Это может вызвать проблемы в будущем, потому что что, если на стадионе откроется новый киоск, и они забудут вызвать код, который проверяет билеты людей.

Преимущества-

  1. Прокси-серверы позволяют вам что-то делать с объектом, используя тот объект, который вы используете, позволяя вам с легкостью написать более чистый, SOLID код.
  2. Если бы это был реальный сценарий, я бы не рассказал охранникам ни о киосках на стадионе, ни продавцам билетов обо всей системе продажи билетов на стадионе. Эти 2 операции могут расти независимо друг от друга.

Эти 2 статьи дают хорошее представление о прокси -

0 голосов
/ 15 мая 2020

Прокси-классы действуют как интерфейс для доступа к объекту, обычно добавляя дополнительные функции.

Они несколько похожи на классы Wrapper, но не содержат объекта, с которым они взаимодействуют, и они необходимы, когда вы необходимо добавить дополнительное поведение к классу, код которого вы не можете изменить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...