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

նախագծման ձևանմուշ

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

Պրոքսի
ՏեսակԿառուցվածքային
ՆշանակությունՕբյեկտի հասանալիությունը կարգավորելու համար
Կառուցվածք
ԱռավելություններՀետևյալն են.
  • հեռակա փոխարինում
  • վիրտուալ փոխարինումը կարող է օպտիմիզացիա իրականացնել
  • պաշտպանված փոխարինում
  • «խելացի» հղում
ԹերություններԱրձագանքների ժամանակի մեծացում
Նկարագրությունը ԳօՖի
"Design Patterns" գրքում
Այո

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

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

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

Ընդհանուր հասկացողություններ խմբագրել

  • 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