Proxy (шаблон проектирования)

Материал из Википедии — свободной энциклопедии

Перейти к: навигация, поиск

Шаблон Proxy (Заместитель) — Шаблон проектирования. Предоставляет объект, контролирующий доступ, перехватывая все вызовы к нему.

Содержание

[править] Цель

[править] Проблема

Необходимо управлять доступом к объекту, так чтобы создавать громоздкие объекты «по требованию».

[править] Решение

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

Диаграмма классов шаблона проектирования Proxy

Шаблон proxy бывает нескольких видов, а именно:

  • Удаленный: обеспечивает связь с «Субъектом» который находится в другом адресном пространстве или на удалённой машине. Так же может отвечать за кодирование запроса и его аргументов и отправку закодированного запроса реальному «Субъекту»,
  • Виртуальный: Обеспечивает создание реального «Субъекта» только тогда, когда он действительно понадобится. Так же может кэшировать часть информации о реальном «Субъекте», чтобы отложить его создание,
  • Копировать-при-записи:: Обеспечивает копирование «субъекта» при выполнении клиентом определённых действий. Частный случай «виртуального прокси»
  • Защищающий: может проверять, имеет ли вызывающий объект необходимые для выполнения запроса права.
  • Кеширующий прокси: Обеспечивает временное хранение результатов расчёта до отдачи множественным клиентам, которые могут разделить эти результаты.
  • Экранирующий прокси: Защищает «Субъект» от опасных клиентов (или наоборот).
  • Синхронизирующий прокси: Производит синхронизированный контроль доступа к «Субъекту» в асинхронной многопоточной среде.
  • Smart reference proxy: Производит дополнительные действиия когда на «Субъект» создается ссылка, например рассчитывает количество активных ссылок на «Субъект».

[править] Плюсы

  •  удаленный заместитель;
  •  виртуальный заместитель может выполнять оптимизацию;
  •  защищающий заместитель;
  • "умная" ссылка;

[править] Минусы

  • резкое увеличение времени отклика.

[править] Применимость

Шаблон Proxy может применяться в таких случаях работы с сетевым соединением, огромным объектом в памяти (или на диске) или любым другим ресурсом который сложно или тяжело копировать. Хорошо известный пример применения — объект подсчитывающий число ссылок.

[править] Примеры

[править] Java

public class Main {
 
	public static void main(String[] args) {
		// Create math proxy
		IMath p = new MathProxy();
 
		// Do the math
		System.out.println("4 + 2 = " + p.add(4, 2));
		System.out.println("4 - 2 = " + p.sub(4, 2));
		System.out.println("4 * 2 = " + p.mul(4, 2));
		System.out.println("4 / 2 = " + p.div(4, 2));
	}
}
 
/**
 * "Subject"
 */
public interface IMath {
 
	public double add(double x, double y);
 
	public double sub(double x, double y);
 
	public double mul(double x, double y);
 
	public double div(double x, double y);
}
 
/**
 * "Real Subject"
 */
public class Math implements IMath {
 
	public double add(double x, double y) {
		return x + y;
	}
 
	public double sub(double x, double y) {
		return x - y;
	}
 
	public double mul(double x, double y) {
		return x * y;
	}
 
	public double div(double x, double y) {
		return x / y;
	}
 
}
 
/**
 * "Proxy Object"
 */
public class MathProxy implements IMath {
 
	private Math math;
 
	public MathProxy() {
		math = new Math();
	}
 
	public double add(double x, double y) {
		return math.add(x, y);
	}
 
	public double sub(double x, double y) {
		return math.sub(x, y);
	}
 
	public double mul(double x, double y) {
		return math.mul(x, y);
	}
 
	public double div(double x, double y) {
		return math.div(x, y);
	}
}

[править] C++

/**
 * "Subject"
 */
class IMath {
public:
    virtual double add(double x, double y) = 0;
    virtual double sub(double x, double y) = 0;
    virtual double mul(double x, double y) = 0;
    virtual double div(double x, double y) = 0;
};
 
/**
 * "Real Subject"
 */
class Math : public IMath {
public:
    double add(double x, double y) {
        return x + y;
    }
 
    double sub(double x, double y) {
        return x - y;
    }
 
    double mul(double x, double y) {
        return x * y;
    }
 
    double div(double x, double y) {
        return x / y;
    }
};
 
/**
 * "Proxy Object"
 */
class MathProxy : public IMath {
public:
    double add(double x, double y) {
        return math.add(x, y);
    }
 
    double sub(double x, double y) {
        return math.sub(x, y);
    }
 
    double mul(double x, double y) {
        return math.mul(x, y);
    }
 
    double div(double x, double y) {
        return math.div(x, y);
    }
 
private:
    Math math;
};
 
#include <iostream>
 
using std::cout;
using std::endl;
 
int main() {
 
    // Create math proxy
    MathProxy p;
 
    // Do the math
    cout << "4 + 2 = " << p.add(4, 2) << endl;
    cout << "4 - 2 = " << p.sub(4, 2) << endl;
    cout << "4 * 2 = " << p.mul(4, 2) << endl;
    cout << "4 / 2 = " << p.div(4, 2) << endl;
 
    return 0;
}

[править] C#

  class MainApp
  {
    static void Main()
    {
      // Create math proxy
      MathProxy p = new MathProxy();
 
      // Do the math
      Console.WriteLine("4 + 2 = " + p.Add(4, 2));
      Console.WriteLine("4 - 2 = " + p.Sub(4, 2));
      Console.WriteLine("4 * 2 = " + p.Mul(4, 2));
      Console.WriteLine("4 / 2 = " + p.Div(4, 2));
 
      // Wait for user
      Console.Read();
    }
  }
 
  // "Subject"
 
  public interface IMath
  {
    double Add(double x, double y);
    double Sub(double x, double y);
    double Mul(double x, double y);
    double Div(double x, double y);
  }
 
   // "RealSubject"
 
  class Math : IMath
  {
    public double Add(double x, double y){return x + y;}
    public double Sub(double x, double y){return x - y;}
    public double Mul(double x, double y){return x * y;}
    public double Div(double x, double y){return x / y;}
  }
 
  // "Proxy Object"
 
  class MathProxy : IMath
  {
    Math math;
 
    public MathProxy()
    {
      math = new Math();
    }
 
    public double Add(double x, double y)
    {
      return math.Add(x,y);
    }
 
    public double Sub(double x, double y)
    {
      return math.Sub(x,y);
    }
 
    public double Mul(double x, double y)
    {
      return math.Mul(x,y);
    }
 
    public double Div(double x, double y)
    {
      return math.Div(x,y);
    }
  }

[править] JavaScript

/* Subject */
function IMath() {
	this.add = function(x, y) {};
	this.sub = function(x, y) {};
}
 
/* Real Subject */
function RMath() {
	/*
	IMath.call(this); // агрегируем IMath, т.к. нативного наследования нет
	// этот вариант следует использовать вместо прототипирования, 
	// если в IMath имеются приватные переменные, 
	// которые могут быть доступны через геттеры в IMath
	*/
	this.add = function(x, y) {
		return x + y;
	};
	this.sub = function(x, y) {
		return x - y;
	};
}
RMath.prototype = new IMath();
RMath.prototype.constructor = RMath;
 
/* Proxy */
function MathProxy() {
	var math = new RMath();
 
	this.add = function(x, y) {
		return math.add(x, y);
	};
	this.sub = function(x, y) {
		return math.sub(x, y);
	};
}
 
var test = new MathProxy();
alert(test.add(3, 2)); // 5
alert(test.sub(3, 2)); // 1

[править] Object Pascal

[править] См. также

[править] Литература


структурные шаблоны проектирования

адаптер | мост | компоновщик | декоратор | фасад | заместитель | приспособленец