— Здравей, Амиго.

„Здравей, Риши.“

„Днес ще ви обясня нова и много интересна тема: динамични проксита“ .

"Java има няколко начина за промяна на функционалността на определен клас..."

— Първият метод е наследяването.

"Най-лесният начин да промените поведението на клас е да създадете нов клас, който наследява оригиналния (базов) клас и да замените неговите методи. След това, instead of да използвате оригиналния клас, вие използвате производния клас. Например:"

Reader reader = new UserCustomReader();

„Вторият метод е да се използва обвиващ клас.“

" BufferedReader е пример за този тип клас. Първо, той наследява Reader . С други думи, може да се използва instead of Reader. Второ, той пренасочва всички извиквания към оригиналния обект Reader , който трябва да бъде предаден на конструктора на обекта BufferedReader . Например:"

Reader readerOriginal = new UserCustomReader();
Reader reader = new BufferedReader(readerOriginal);

„Третият метод е да създадете динамичен прокси (Proxy).“

"В Java има специален клас (java.lang.reflect.Proxy), който всъщност ви позволява да конструирате обект по време на изпълнение на програмата (динамично), без да създавате отделен клас за него."

„Това се прави много лесно:“

Reader reader = (Reader)Proxy.newProxyInstance();

— Това вече е нещо ново за мен!

„Но разбира се, ние не се нуждаем от обект без методи. Нуждаем се от обекта да има методи и ние се нуждаем от тях, за да правят това, което искаме. Java използва специален интерфейс за това, наречен InvocationHandler, който може да прихваща всички извиквания на методи свързан с прокси обекта. Прокси обект може да бъде създаден само с помощта на интерфейси."

" Invoke – е стандартното име за метод or клас, чиято основна задача е просто да извика няHowъв метод."

" Handler – е стандартното име за клас, който обработва няHowво събитие. Например, клас, който обработва щраквания на мишката, ще се нарича MouseClickHandler и т.н."

"Интерфейсът InvocationHandler има един единствен метод за извикване, към който са насочени всички извиквания към прокси обекта . Например:"

Код
Reader reader = (Reader)Proxy.newProxyInstance(new CustomInvocationHandler());
reader.close();
class CustomInvocationHandler implements InvocationHandler
{
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
 {
  System.out.println("yes!");
  return null;
 }
}

"Когато извиквате метода reader . close (), методът за извикване ще бъде извикан и екранът ще покаже "да!""

„И така, ние декларирахме CustomInvocationHandler, клас, и внедрихме интерфейса InvocationHandler и неговия метод за извикване . Когато методът за извикване се извика, той показва „да!“. След това създадохме обект CustomInvocationHandler и го предадохме на метода newProxyInstance при създаването прокси обект."

— Да, всичко е вярно.

„Това е много мощен инструмент. Обикновено тези проксита се създават за симулиране на обекти в програми, които физически се изпълняват на друг компютър.  Или за контрол на достъпа.“

„Можете да проверите разрешенията на текущия потребител, да обработвате грешки, грешки в журнала и много повече в този метод.“

„Ето пример, при който методът за извикване също извиква методите на оригиналния обект:“

Код
Reader original = new UserCustomReader();

Reader reader = (Reader)Proxy.newProxyInstance(new CustomInvocationHandler(original));
reader.close();
class CustomInvocationHandler implements InvocationHandler
{
 private Reader readerOriginal;

 CustomInvocationHandler(Reader readerOriginal)
 {
  this.readerOriginal = readerOriginal;
 }

 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
 {
  if (method.getName().equals("close"))
  {
   System.out.println("Reader closed!");
  }

  // This calls the readerOriginal object's close method.
  // The method's name and a description of its parameters are stored in the method variable.
  return method.invoke(readerOriginal, args);
 }
}

„Този ​​пример има две специални характеристики.“

„Първо, „оригиналния“ обект Reader се предава на конструктора и препратката към него се записва в CustomInvocationHandler .

„Второ, извикваме същия този метод отново в метода за извикване, но този път върху „оригиналния“ обект.“

"Ах. С други думи, този последен ред извиква същия метод, но на оригиналния обект:"

return method.invoke(readerOriginal, args);

— Да.

„Не бих казал, че е супер очевидно, но все пак е разбираемо. Или поне така изглежда.“

„Страхотно. Тогава още нещо. В метода newProxyInstance трябва да предадете малко повече информация за поддръжка, за да създадете прокси обект. Но тъй като ние не създаваме чудовищни ​​прокси обекти, тази информация се получава лесно от самия оригинален клас. "

„Ето още един пример:“

Код
Reader original = new UserCustomReader();

ClassLoader classLoader = original.getClass().getClassLoader();
Class<?>[] interfaces = original.getClass().getInterfaces();
CustomInvocationHandler invocationHandler = new CustomInvocationHandler(original);

Reader reader = (Reader)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
class CustomInvocationHandler implements InvocationHandler
{
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
 {
  return null;
 }
}

„Ах. ClassLoader и списък с интерфейси. Това е нещо от Reflection, нали?“

— Да.

„Разбирам. Е, мисля, че мога да създам примитивен, супер прост прокси обект, ако някога имам нужда от такъв.“

— Тогава отидете да се регистрирате при Диего.