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

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

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

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

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

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

Կառուցվածք

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

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

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

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

Առավելություններ և թերություններ

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

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

Օրինակներ

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

Ծանոթագրություններ 

Ծրագրավորում