Helyettes programtervezési minta

A Wikipédiából, a szabad enciklopédiából
Helyettes UML-ben
Helyettes LePUS3-ban (legend)

A számítástudományban a helyettes minta vagy helyettesítő minta egy programtervezési minta.

Egy helyettes a legáltalánosabb formájában egy olyan osztály funkcionalitása, amely egy interfész valami máshoz. A helyettes interfészként tud viselkedni valamihez: egy hálózati kapcsolathoz, egy nagy objektumhoz a memóriában, egy fájlhoz vagy számos más erőforráshoz, amely költséges vagy lehetetlen duplikálni.

A helyettes programtervezési mintára egy jól ismert példa egy referencia számláló mutató objektum.

Olyan esetekben, ahol egy összetett objektum több példányának kell léteznie, a helyettesítő minta adaptálható a pehelysúlyú mintára, azért hogy csökkentse az alkalmazás memóriában elfoglalt méretét. Tipikus módon az összetett objektumból 1 példány és sok helyettes objektum készül, melyek tartalmaznak az egy darab eredeti összetett objektumra mutató referenciát. Bármilyen művelet végrehajtása a helyettesítőkön az eredeti objektumnak való továbbítást jelent. Amint az összes helyettes példány érvényessége megszűnik, az összetett objektum tárhelye felszabadíthatóvá válik.

Használata[szerkesztés]

A helyettes megvalósítja az eredeti objektum interfészét. Információkat rejthet el, kérésre végezhet optimalizációt vagy betöltést. Elláthat további feladatokat is, mint auditálás vagy naplózás.

A védelmi helyettes ellenőrzi a hozzáférést, és csak megfelelő jogosultság esetén engedélyezi.

A virtuális helyettes egy erőforrás-igényes objektumot helyettesít, és csak akkor tölti be, ha tényleg szükség van az eredeti objektumra.

A távoli helyettes egy távoli objektumot reprezentál helyben, és ha metódushívás történik, akkor továbbítja a távoli objektumnak. Például az ATM automaták így állnak kapcsolatban a bankkal.

A helyettes tesztelési célra is használható, ekkor fake, stub vagy mock objektum a neve.

Példák[szerkesztés]

A következő Java példa a "virtuális helyettes" mintát szemlélteti. A ProxyImage osztály használható egy távoli metódus eléréséhez.

A példa először létrehoz egy interfészt, amihez a minta szerint létrehozzuk a megvalósító osztályokat. Ez az interfész csak egy metódust tartalmaz, amely megjeleníti a képet (displayImage()), és ezt kell lekódolni az összes osztálynak, amely azt megvalósítja.

A helyettes osztály a ProxyImage egy másik rendszerben fut, mint a valódi kép osztály maga és reprezentálja a valódi osztályt RealImage a felett. A kép információk elérhetők a lemezről. A helyettes minta használatával a ProxyImage kódja elkerüli a kép többszöri betöltését, elérhetővé téve azt egy másik rendszerből memóriatakarékos módon.

interface Image {
    public void displayImage();
}

//on System A 
class RealImage implements Image {

    private String filename = null;
    /**
     * Constructor
     * @param FILENAME
     */
    public RealImage(final String FILENAME) { 
        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) { 
        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
    }

}

A program kimenete:

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

C#[szerkesztés]

A következő C# és C++ példa a védelmi helyettest szimulálja.

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;
        this.realCar = new Car();
    }

    public void DriveCar()
    {
        if (driver.Age <= 16)
            Console.WriteLine("Sorry, the driver is too young to drive.");
        else
            this.realCar.DriveCar();
     }
}

public class Driver
{
    private 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();
}

Kimenet:

Sorry, the driver is too young to drive.
Car has been driven!

C++[szerkesztés]

class ICar {
public:
  virtual void DriveCar() = 0;
};

class Car : public ICar {
  void DriveCar() override {
    std::cout << "Car has been driven!" << std::endl;
  }
};

class ProxyCar : public ICar {
private:
  ICar* realCar = new Car();
  int _driver_age;

public:
  ProxyCar (const int driver_age) : _driver_age(driver_age) {}

  void DriveCar() {
    if (_driver_age > 16)
      realCar->DriveCar();
    else
      std::cout << "Sorry, the driver is too young to drive." << std::endl;
  }
};

// How to use above Proxy class?
void main()
{
    ICar* car = new ProxyCar(16);
    car->DriveCar();
    delete car;

    car = new ProxyCar(25);
    car->DriveCar();
    delete car;
}

Kapcsolódó szócikkek[szerkesztés]

Jegyzetek[szerkesztés]

További információk[szerkesztés]

Az angol Wikikönyvekben
további információk találhatók

Fordítás[szerkesztés]

Ez a szócikk részben vagy egészben a Proxy pattern című angol Wikipédia-szócikk ezen változatának fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.