Պրոքսի (նախագծման ձևանմուշ)
Պրոքսի (անգլ.՝ Proxy), կառուցվածքային նախագծման ձևանմուշ, որը տրամադրում է մեկ այլ օբյեկտի հասանելիությունը ղեկավորող օբյեկտ։ Այդ օբյեկտը բոլոր կանչերը վերցնում է իր վրա։
Ընդհանուր առմամբ Պրոքսին իրենից ներկայացնում է դասի ինտերֆեյս կամ դրա նման մի բան։ Պրոքսին կարող է ինտերֆեյս ունենալ ամեն ինչին՝ համացանցին, հիշողության մեջ մեծ օբյեկտին, ֆայլին կամ մեկ այլ ռեսուրսի, որը «թանկարժեք» է կամ անհնար է վերարտադրել։
Պրոքսի ձևանմուշի լավ օրինակ է հղումների հաշվումը խելացի ցուցիչ օբյեկտը։
Այն դեպքերում, երբ հարկ է լինում օգտագործել բարդ օբյեկտների կրնօրինակներ, պրոքսի ձևանմուշը կարելի է իրականացնել հարմարեցնող ձևանմուշով, որի միջոցով կարելի է նվազեցնել անհրաժեշտ հիշողության չափը։ Հատկանշական է այն, որ բարդ նմուշի պատճենները և պրոքսիի բազմակի օբյեկտները ստեղծվում են որպես ցուցիչներ մեկ օրիգինալ բարդ օբյեկտի վրա։ Պրոքսիների կողմից իրականացված ցանկացած գործողություն ուղարկվում է օրիգնալ օբյեկտի վրա։ Երբ արդեն պրոքսիի բոլոր նմուշները իրենց աշխատանքն իրականացրել են, բարդ օբյեկտի զբաղեցրած հիշողությունը կարելի է ազատել։
Ընդհանուր հասկացողություններ
[խմբագրել | խմբագրել կոդը]- Client - հայցող
- Instance - նմուշ
- Implementation - իրականացում
- Product - արգասիք
Կառուցվածք
[խմբագրել | խմբագրել կոդը]Կիրառություն
[խմբագրել | խմբագրել կոդը]Պրոքսի ձևանմուշը այլ օբյեկտների համար ինտերֆեյս է տրամադրում դասը՝ որպես պրոքսի ծրարելով (անգլ.՝ wrap)։ Պրոքսի հանդիսացող ծրարված դասի (անգլ.՝ wrapper class) մեջ կարելի է ավելացնել օբյեկտի լրացուցիչ ֆունկցիոնալություն՝ առանց փոփոխություն անելու օբյեկտի կոդում։
Ստորև բերված է տարածված օրինակներ, որտեղ օգտագործվում է պրոքսի ձևանմուշը.
- Գոյություն ունեցող օբյեկտի համար անվտանգության ապահովում։ Պրոքսին կորոշի, թե հայցողը կարող է հասանելիություն ստանալ օբյեկտին, թե՝ ոչ։
- API բարդ օբյեկտների պարզեցում։ Պրոքսին կարող է ավելի պարզ API տրամադրել և հայցողի կոդը այնքան բարդ չի լինի, որքան օբյեկտինը։
- Հեռակա ռեսուրսների համար ինտերֆեյսի տրամադրում։ Օրինակ վեբ ծառայություններ կամ REST ռեսուրսներ։
- Հեռակա ռեսուրսների վրա կիրառվող գործողությունների կոորդինացում, որպեսզի աշխատանքը սկսվի հնարավորնիս շուտ մինչ այն կհասնի ռեսուրսին։
- Հոսքատիպ ֆունկցիաներ ավելանցելով գոյություն ունեցող դասին՝ առանց փոփոխելով գոյություն ունեցող դասը։
Կարճ ասած, պրոքսին հանդիսանում է օբյեկտ, որն հասանելիություն ունի ռեալ օբյեկտին։
Տարատեսակներ
[խմբագրել | խմբագրել կոդը]- Պրոտակոլիզացնող պրոքսի - լոգի մեջ պահում է «Սուբյեկտի» բոլոր կանչերն իր պարամետրերով
- Հեռակա փոխարինիչ (անգլ.՝ remote proxies) - ապահովում է կապ «Սուբյեկտի» հետ, որը գտնվում է մեկ այլ անվատարածքում կամ էլ հեռակա մեքենայում։ Ինչպես նաև կարող է պատասխանատու լինել հարցման և նրա արգումնետների կոդավորման և հարցումը ռեալ «Սուբյեկտին» կոդավորված ձևով ուղարկելով։
- Վիրտուալ փոխարինիչ (անգլ.՝ virtual proxies) - ռեալ «Սուբյեկտի» ստեղծումը ապահովում է միայն այն ժամանակ, երբ այն անհրաժեշտ է։ Ինչպես նաև կարող է ռեալ «Սուբյեկտին» ինֆորմացիայի մի մասը քեշավորել, որպեսզի նրա ստեղծումը հետաձգի։
- Գրելու ժամանակ պատճենում - ապահովում է «Սուբյեկտի» պատճենումը հայցողի կողմից որոշակի գործողություններ կատարելիս։ Հանդիսանում է «Վիրտուալ պրոքսիի» մասնավոր դեպք։
- Պաշտպանող փոխարինիչ (անգլ.՝ protection proxies - կարող է ստուգել, թե կանչված օբյեկտը հարցումը կատարելու իրավունք ունի, թե ոչ։
- Քեշավորող պրոքսի - ապահովում է տվյալների ժամանակավոր պահպանում մի քանի հայցողների համար, որոնց համար անհրաժեշտ է այդ ինֆորմացիան։
- Էկրանավորող պրոքսի պաշտպանում է «Սուբյեկտին» վտանգավոր հայցողներից (կամ հակառակը)։
- Սինխրոնիզացնող պրոքսի - իրականացնում է սինխրոնիզացված հասանելիություն «Սուբյեկտի» նկատմամբ ասինխրոն բազմահոս միջավայրում։
- «Խելացի» հղում (անգլ.՝ smart reference proxy) - իրականացնում է լրացուցիչ գործողություններ, երբ «Սուբյեկտի» վրա ստեղծվում է ցուցիչ։ Օրինակ հաշվարկում է «Սուբյեկտի» վրա եղած ակտիվ ցուցիչների քանակը։
Առավելություններ և թերություններ
[խմբագրել | խմբագրել կոդը]Առավելություններ
[խմբագրել | խմբագրել կոդը]- Հեռակա փոխարինիչ
- Վիրտուալ փոխարինիչը կարող է իրականացնել ցանկացած օպտիմիզացիա
- Պաշտպանող փոխարինչ
- «Խելացի» հղում
Թերություններ
[խմբագրել | խմբագրել կոդը]- Արձագանքի ժամանակի կտրուկ մեծացում
Օրինակներ
[խմբագրել | խմբագրել կոդը]C++
[խմբագրել | խմբագրել կոդը]class ICar {
public:
virtual void DriveCar() = 0;
};
class Car : public ICar {
public:
Car(int driver_age, ICar* pCar) : _pImpl(pCar), _driver_age(driver_age) {}
void DriveCar() {
if (_driver_age >= 16)
_pImpl->DriveCar();
}
private:
ICar* _pImpl;
int _driver_age;
};
C#
[խմբագրել | խմբագրել կոդը]//IVSR: Proxy Design pattern
namespace IVSR.DesignPattern.Proxy
{
interface ICar
{
void DriveCar();
}
//Real Object
public class Car : ICar
{
public void DriveCar()
{
Console.WriteLine("Car has been driven!");
}
}
//Proxy Object
public class ProxyCar : ICar
{
private Driver driver;
private ICar realCar;
public ProxyCar(Driver driver)
{
this.driver = driver;
realCar = new Car();
}
public void DriveCar()
{
if (driver.Age <= 16)
Console.WriteLine("Sorry, the driver is too young to drive.");
else
realCar.DriveCar();
}
}
public class Driver
{
public int Age { get; set; }
public Driver(int age)
{
this.Age = age;
}
}
//How to use above Proxy class?
private void btnProxy_Click(object sender, EventArgs e)
{
ICar car = new ProxyCar(new Driver(16));
car.DriveCar();
car = new ProxyCar(new Driver(25));
car.DriveCar();
}
}
Ելք.
Sorry, the driver is too young to drive. Car has been driven!
Նոթեր.
- Պրոքսին կարող է թաքցնել ռեալ օբյեկտի մասին տեղեկությունը հայցողից։
- Պրոքսին կարող է օպտիմիզացումներ անել՝ օրինակ թեթևացնել ծանրաբեռնվածությունը
- Պրոքսի ձևանմուշը հայտնի է նաև որպես նախագծման սուռագատային ձևանմուշ
Java
[խմբագրել | խմբագրել կոդը]interface Image {
public void displayImage();
}
//on System A
class RealImage implements Image {
private String filename = null;
/**
* Constructor
* @param filename
*/
public RealImage(final String filename) {
this.filename = filename;
loadImageFromDisk();
}
/**
* Loads the image from the disk
*/
private void loadImageFromDisk() {
System.out.println("Loading " + filename);
}
/**
* Displays the image
*/
public void displayImage() {
System.out.println("Displaying " + filename);
}
}
//on System B
class ProxyImage implements Image {
private RealImage image = null;
private String filename = null;
/**
* Constructor
* @param filename
*/
public ProxyImage(final String filename) {
this.filename = filename;
}
/**
* Displays the image
*/
public void displayImage() {
if (image == null) {
image = new RealImage(filename);
}
image.displayImage();
}
}
class ProxyExample {
/**
* Test method
*/
public static void main(String[] args) {
final Image IMAGE1 = new ProxyImage("HiRes_10MB_Photo1");
final Image IMAGE2 = new ProxyImage("HiRes_10MB_Photo2");
IMAGE1.displayImage(); // loading necessary
IMAGE1.displayImage(); // loading unnecessary
IMAGE2.displayImage(); // loading necessary
IMAGE2.displayImage(); // loading unnecessary
IMAGE1.displayImage(); // loading unnecessary
}
}
Ծրագրի ելքերն են.
Loading HiRes_10MB_Photo1 Displaying HiRes_10MB_Photo1 Displaying HiRes_10MB_Photo1 Loading HiRes_10MB_Photo2 Displaying HiRes_10MB_Photo2 Displaying HiRes_10MB_Photo2 Displaying HiRes_10MB_Photo1
|