Wzorzec projektowy Pełnomocnik (ang. Proxy)

Stosowalność

Pełnomocnik ma zastosowanie zawsze wtedy, kiedy potrzeba bardziej uniwersalnego lub bardziej wyrafinowanego odwołania do obiektu niż zwykły wskaźnik.

Rodzaje

Istnieją cztery rodzaje tego wzorca, które jednocześnie definiują sytuacje, w których może zostać użyty:

  • wirtualny - przechowuje obiekty, których utworzenie jest kosztowne; tworzy je na żądanie
  • ochraniający - kontroluje dostęp do obiektu sprawdzając, czy obiekt wywołujący ma odpowienie prawa do obiektu wywoływanego
  • zdalny - czasami nazywany ambasadorem; reprezentuje obiekty znajdujące się w innej przestrzeni adresowej
  • sprytne odwołanie - czasami nazywany sprytnym wskaźnikiem; pozwala na wykonanie dodatkowych akcji podczas dostępu do obiektu, takich jak: zliczanie referencji do obiektu czy ładowanie obiektu do pamięci

Struktura

Uczestnicy

  • Pełnomocnik
    • przechowuje odwołanie, które umożliwia mu dostęp do prawdziwego przedmiotu; może odwoływać się do przedmiotu, jeśli interfejsy Przedmiotu i prawdziwegoPrzedmiotu są takie same;
    • zapewnia taki sam interfejs jak interfejs Przedmiotu, tak że Pełnomocnik może być zastąpiony przez Przedmiot;
    • kontroluje dostęp do prawdziwego przedmiotu i może być odpowiedzialny za tworzenie oraz usuwanie tego przedmiotu;
    • inne obowiązki zależą od rodzaju pełnomocnika:
      • pełnomocnicy zdalni są odpowiedzialni za kodowanie żądań i ich argumentów oraz za wysyłanie zakodowanych żądań do rzeczywistych przedmiotów w innej przestrzeni adresowej;
      • pełnomocnicy wirtualni mogą przechowywać w pamięci podręcznej dodatkowe informacje o rzeczywistym przedmiocie, dzięki czemu mogą odłożyć na później uzyskanie dostępu do niego;
      • pełnomocnicy ochraniający sprawdzają, czy wywołujący ma zezwolenie na dostęp, wymagane na spełnienie danego żądania.
  • Przedmiot
    • definiuje wspólny interfejs dla PrawdziwegoPrzedmiotu i Pełnomocnika, tak żeby Pełnomocnik mógł być używany wszędzie tam, gdzie jest oczekiwany PrawdziwyPrzedmiot.
  • PrawdziwyPrzedmiot
    • definiuje rzeczywisty obiekt reprezentowany przez pełnomocnika.

Współpraca

Pełnomocnik, jeśli trzeba przekazuje żądania do PrawdziwegoPrzedmiotu (w zależności od rodzaju pełnomocnika).

Implementacja

using System;
using System.Collections.Generic;
using System.Text;
public interface IDude
{
string Name { get; set; }
void GotShot(string typeOfGun);
}
//zwykły obiekt NormalDude
public class NormalDude: IDude
{
private string m_Name = string.Empty;
private bool m_IsHurt = false;
public string Name
{
get{ return m_Name;}
set{ m_Name = value; }
}
public void GotShot(string typeOfGun)
{
m_IsHurt = true;
Console.WriteLine(m_Name + " zostal postrzelony z " +
typeOfGun );
}
public override string ToString()
{
StringBuilder result = new StringBuilder();
result.Append(m_Name);
if(m_IsHurt)
{
result.Append(" jest ranny ");
}
else
{
result.Append(" jest zdrowy jak kon");
}
return result.ToString();
}
}
//a tu ochrona (protexion proxy) dla naszego obiektu typu NormalDude
//jeśli obiekt SuperDude zostanie postrzelony zachowuje sie jakby był
//tarczą dla naszego obiektu NormalDude
//?aden NormalDude chroniony przez SuperDude nie mo?e być zraniony
//my mamy dośtęp tylko chronionyh (przez pośrednika) obiektów
public class SuperDude : IDude
{
private IDude m_dude;
public SuperDude(IDude dude)
{
m_dude = dude;
}
#region IDude Members
public string Name
{
get { return "Super" + m_dude.Name; }
set { m_dude.Name = value; }
}
public void GotShot(string typeOfGun)
{
StringBuilder result = new StringBuilder();
result.Append(this.Name).Append(" zostal postrzelony z
").Append(typeOfGun);
result.Append("ale pocisk sie odbil!!! \nnie mozesz zranic
").Append(this.Name);
result.Append("\n\n");
Console.WriteLine(result.ToString());
// Uwaga!: GotShot() wywołujemy na obiekcie opakowanym w proxy
}
#endregion
public override string ToString()
{
StringBuilder result = new StringBuilder();
result.Append(Name).Append("nie mo?e zostac zraniony!");
result.Append(" (").Append(Name).Append("jest super-proxybohaterem).\
n");
return result.ToString();
}
}
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
ConsoleKeyInfo cki;
StringBuilder sb = new StringBuilder();
Console.TreatControlCAsInput = true;
do
{
//tu sie dzieje magia
cki = Console.ReadKey(true);
IDude Joe = new NormalDude();//tworzymy NormalDude Zwyczajnego
Jana Kowalskiego
Joe.Name = "Zwyczjany Jan Kowalski";
IDude Clark = new NormalDude();// tworzymy NormalDude Claka
Clark.Name = "Clark";
Clark = new SuperDude(Clark); // nakładamy Clarkowi peleryne
super bohatera
Console.WriteLine("Nadchodza strzelajacy bandyci! Kule nisko
lataja! \n\n");
Joe.GotShot("Uzi");
Clark.GotShot("Bazooki");
Console.WriteLine(Joe.ToString());
Console.WriteLine(Clark.ToString());
} while (cki.Key != ConsoleKey.Escape);
}
}
}