Պրոքսի (նախագծման ձևանմուշ)

**Պրոքսի** (), կառուցվածքային նախագծման ձևանմուշ, որը տրամադրում է մեկ այլ օբյեկտի հասանելիությունը ղեկավորող օբյեկտ։ Այդ օբյեկտը բոլոր կանչերը վերցնում է իր վրա։

Ընդհանուր առմամբ Պրոքսին իրենից ներկայացնում է դասի ինտերֆեյս կամ դրա նման մի բան։ Պրոքսին կարող է ինտերֆեյս ունենալ ամեն ինչին՝ համացանցին, հիշողության մեջ մեծ օբյեկտին, ֆայլին կամ մեկ այլ ռեսուրսի, որը «թանկարժեք» է կամ անհնար է վերարտադրել։

Պրոքսի ձևանմուշի լավ օրինակ է հղումների հաշվումը խելացի ցուցիչ օբյեկտը։

Այն դեպքերում, երբ հարկ է լինում օգտագործել բարդ օբյեկտների կրնօրինակներ, պրոքսի ձևանմուշը կարելի է իրականացնել հարմարեցնող ձևանմուշով, որի միջոցով կարելի է նվազեցնել անհրաժեշտ հիշողության չափը։ Հատկանշական է այն, որ բարդ նմուշի պատճենները և պրոքսիի բազմակի օբյեկտները ստեղծվում են որպես ցուցիչներ մեկ օրիգինալ բարդ օբյեկտի վրա։ Պրոքսիների կողմից իրականացված ցանկացած գործողություն ուղարկվում է օրիգնալ օբյեկտի վրա։ Երբ արդեն պրոքսիի բոլոր նմուշները իրենց աշխատանքն իրականացրել են, բարդ օբյեկտի զբաղեցրած հիշողությունը կարելի է ազատել։

## Ընդհանուր հասկացողություններ
* Client - հայցող
* Instance - նմուշ
* Implementation - իրականացում
* Product - արգասիք

## Կառուցվածք
500px

## Կիրառություն
Պրոքսի ձևանմուշը այլ օբյեկտների համար ինտերֆեյս է տրամադրում դասը՝ որպես պրոքսի ծրարելով ()։ Պրոքսի հանդիսացող ծրարված դասի () մեջ կարելի է ավելացնել օբյեկտի լրացուցիչ ֆունկցիոնալություն՝ առանց փոփոխություն անելու օբյեկտի կոդում։

Ստորև բերված է տարածված օրինակներ, որտեղ օգտագործվում է պրոքսի ձևանմուշը.
* Գոյություն ունեցող օբյեկտի համար անվտանգության ապահովում։ Պրոքսին կորոշի, թե հայցողը կարող է հասանելիություն ստանալ օբյեկտին, թե՝ ոչ։
* API բարդ օբյեկտների պարզեցում։ Պրոքսին կարող է ավելի պարզ API տրամադրել և հայցողի կոդը այնքան բարդ չի լինի, որքան օբյեկտինը։
* Հեռակա ռեսուրսների համար ինտերֆեյսի տրամադրում։ Օրինակ վեբ ծառայություններ կամ REST ռեսուրսներ։
* Հեռակա ռեսուրսների վրա կիրառվող գործողությունների կոորդինացում, որպեսզի աշխատանքը սկսվի հնարավորնիս շուտ մինչ այն կհասնի ռեսուրսին։
* Հոսքատիպ ֆունկցիաներ ավելանցելով գոյություն ունեցող դասին՝ առանց փոփոխելով գոյություն ունեցող դասը։

Կարճ ասած, պրոքսին հանդիսանում է օբյեկտ, որն հասանելիություն ունի ռեալ օբյեկտին։

## Տարատեսակներ
* **Պրոտակոլիզացնող պրոքսի** - լոգի մեջ պահում է «Սուբյեկտի» բոլոր կանչերն իր պարամետրերով
* **Հեռակա փոխարինիչ** () - ապահովում է կապ «Սուբյեկտի» հետ, որը գտնվում է մեկ այլ անվատարածքում կամ էլ հեռակա մեքենայում։ Ինչպես նաև կարող է պատասխանատու լինել հարցման և նրա արգումնետների կոդավորման և հարցումը ռեալ «Սուբյեկտին» կոդավորված ձևով ուղարկելով։
* **Վիրտուալ փոխարինիչ** () - ռեալ «Սուբյեկտի» ստեղծումը ապահովում է միայն այն ժամանակ, երբ այն անհրաժեշտ է։ Ինչպես նաև կարող է ռեալ «Սուբյեկտին» ինֆորմացիայի մի մասը քեշավորել, որպեսզի նրա ստեղծումը հետաձգի։
* **Գրելու ժամանակ պատճենում** - ապահովում է «Սուբյեկտի» պատճենումը հայցողի կողմից որոշակի գործողություններ կատարելիս։ Հանդիսանում է «Վիրտուալ պրոքսիի» մասնավոր դեպք։
* **Պաշտպանող փոխարինիչ** ( - կարող է ստուգել, թե կանչված օբյեկտը հարցումը կատարելու իրավունք ունի, թե ոչ։
* **Քեշավորող պրոքսի** - ապահովում է տվյալների ժամանակավոր պահպանում մի քանի հայցողների համար, որոնց համար անհրաժեշտ է այդ ինֆորմացիան։
* **Էկրանավորող պրոքսի** պաշտպանում է «Սուբյեկտին» վտանգավոր հայցողներից (կամ հակառակը)։
* **Սինխրոնիզացնող պրոքսի** - իրականացնում է սինխրոնիզացված հասանելիություն «Սուբյեկտի» նկատմամբ ասինխրոն բազմահոս միջավայրում։
* **«Խելացի» հղում** () - իրականացնում է լրացուցիչ գործողություններ, երբ «Սուբյեկտի» վրա ստեղծվում է ցուցիչ։ Օրինակ հաշվարկում է «Սուբյեկտի» վրա եղած ակտիվ ցուցիչների քանակը։

## Առավելություններ և թերություններ
### Առավելություններ
* Հեռակա փոխարինիչ
* Վիրտուալ փոխարինիչը կարող է իրականացնել ցանկացած օպտիմիզացիա
* Պաշտպանող փոխարինչ
* «Խելացի» հղում

### Թերություններ
* Արձագանքի ժամանակի կտրուկ մեծացում

## Օրինակներ
### C++

```cpp
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#

```csharp
//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

```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

Կատեգորիա:Ծրագրավորում