Vekil Kalıp (Proxy Pattern)

Eyl 08, 2013
Vekil kalıp (Proxy Pattern), nesne temelli yazılım mimarilerinde belirlenmiş temel tasarım kalıplarından biridir. Var olan bir nesneye ulaşılmak istendiğinde vekil kalıp oluşturulur. Nesneyle istemci arasına yeni bir katman koyarak nesnenin kontrollü bir şekilde paylaşılması sağlanır. Böylece istemci, işlem yapan sınıfla doğrudan temasa geçmemiş olur. Bu durum sayesinde işlemin yapılma performansında bir düşüklük olmaması sağlanır. Bu yüzden vekil kalıp fazla yük getiren işlemlerde kullanılır. Mesela; bir film sitesinden film izlenirken, filmin indirilmesi beklenmez. Arka tarafta vekil tasarım kalıbı oluşturularak parça parça işlem yapılır ve zaman kaybı önlenmiş olur. Burada film gerçek nesne (realsubject), izlenen ise vekil nesne (proxy) olur.

Vekil tasarım deseni;
  • Oluşturulması zaman alan bir nesne yaratılması gerektiğinde
  • Uzaktan erişilerek bir nesne yaratılması gerektiğinde
  • Nesneye erişmeden önce bazı kontroller yapılması gerektiğinde
  • Nesneye erişimin kısıtlı olduğunda yararlı olabilir.

Tasarım Şablonunun Gerçeklenmesi

Vekil kalıp tasarım kalıbında bir gerçek nesne bir de vekil nesne vardır. Vekil nesne gerçek nesnenin fonksiyonlarını kullanır. Yani istemci, işlemini vekil nesne üzerinden yapar. Bu yüzden gerçek nesnenin yapacağı iş vekil nesnenin kararıyla belirlenir. Vekil nesne sayesinde nesneye erişim sıklıkla olmayacak ve işlem daha verimli olacaktır.

Vekil tasarım kalıbının UML diyagramı aşağıdaki şekildedir;

 

Vekil Kalıp İle İlgili Uygulama

Hazırlanan örnek uygulamada bir video dosyası byte-byte kopyalanacak ve daha sonra bu kopyalanan dosya oynatılacaktır. Bunun için bir WPF (Windows Presentation Foundation) projesi açılıp, gerekli sınıflar oluşturulur. Öncelikle kopyalama işlemi için "Kopyalayici" isimli sınıf oluşturulur. Yapıcı metot içerisinde "Kopyala" isimli metot çağrılır ve böylece kopyalama işlemi tetiklenir.

//Gerçek nesne
class Kopyalayici

{
     string kaynak;
     string hedef;

     public Kopyalayici(string kaynak, string hedef)

     {
          this.kaynak = kaynak;

          this.hedef = hedef;

          Kopyala();

     }

     public void Kopyala()

     {
          //okuma stream'i
          FileStream streamIn = new FileStream(kaynak, FileMode.Open);

          //yazma stream'i
          FileStream streamOut = new FileStream(hedef, FileMode.Create);

 

          //veri okuma

          byte[] okunan = new byte[streamIn.Length];

           

          streamIn.Read(okunan, 0, okunan.Length);

          streamIn.Close();

 

          //veri yazma

          streamOut.Write(okunan, 0, okunan.Length);

          streamOut.Close();

     }
}

Kopyalama işlemi için kaynak dosya okuma modunda, hedef dosya ise yaratma modunda açılır. Daha sonra byte dizisi aracılığıyla byte-byte okuma ve yazma işlemleri gerçekleştirilir.

"KopyalayiciProxy" isimli sınıfta ise Kopyalayici türünden bir adet nesne oluşturulur. Ancak daha önce oluşturulan bir nesnenin tekrar oluşturulmasını engellemek amacıyla if koşulu kullanılır. Kopyala metodundan geriye dönen boolean değer ile kullanıcı bilgilendirilir.

//Proxy nesne 
class KopyalayiciProxy

{

     Kopyalayici kopyalayici;

 

     public KopyalayiciProxy() { }

 

     public bool Kopyala(string kaynak, string hedef)

     {

          bool sonuc;

 

          if (kopyalayici == null)

          {

               sonuc = true;

               kopyalayici = new Kopyalayici(kaynak, hedef);

          }

          else

          {

               sonuc = false;

          }

 

          return sonuc;

     }

}

 

Oluşturulan sınıfları kullanacak WPF formunun tasarımı ise aşağıdaki gibidir.

 

<Grid>

     <MediaElement Height="282" HorizontalAlignment="Left" Margin="36,51,0,0"
     Name="mediaElemet1" VerticalAlignment="Top" Width="381"
     LoadedBehavior="Manual" UnloadedBehavior="Stop"
     Stretch="Fill"></MediaElement>

     <Label Content="bilgi" Height="28" HorizontalAlignment="Left"
     Margin="193,10,0,0" Name="bilgiLabel" VerticalAlignment="Top"></Label>

     <Button Content="Button" Height="23" HorizontalAlignment="Left"
     Margin="193,12,0,0" Name="button1" VerticalAlignment="Top" Width="75"
     Click="button1_Click" />

</Grid>

Oluşturulan WPF formun sınıfında bulunan "hedefDosya" isimli dosya, kopyalama işlemi yapıldıktan sonra kullanılacak olan dosyadır. Uygulamada asıl işlemi yerine getiren sınıf "Kopyalayici" isimli sınıf olmasına rağmen, istemci doğrudan bu sınıfa erişmemektedir. "KopyalayiciProxy" sınıfı üzerindeki metot aracılığıyla gerçek nesneye görev gönderimi yapılıp yapılmayacağına karar verilir.

public partial class MainWindow : Window
{
     public MainWindow()
     {
          InitializeComponent();
     }

     KopyalayiciProxy proxy = new KopyalayiciProxy();
     Stopwatch saat = new Stopwatch();
     string kaynakDosya = @"D:\MTvideo.wmv";
     string hedefDosya = @"D:\MTvideo1.wmv";

     private void button1_Click(object sender, RoutedEventArgs e)
     {
          saat.Restart();
          bool sonuc = proxy.Kopyala(kaynakDosya, hedefDosya);
          saat.Stop();

          if (sonuc)
          {
               bilgiLabel.Content = "Kopyalandı. Süre: "
                             + saat.Elapsed.TotalMilliseconds.ToString();
          }
          else
          {
               bilgiLabel.Content = "Daha önceki kopya kullanılıyor. Süre: "
                             +saat.Elapsed.TotalMilliseconds.ToString();
          }

          //Video oynat
          mediaElemet1.Source = new Uri(hedefDosya);
          mediaElemet1.Play();
     }
}

 
Uygulama çalıştırıldığında ilk olarak oynatılacak dosyanın açılma süresi yaklaşık 0,5 sn iken ikinci kez oynatılmak istenildiğinde 0,002 sn olarak görülmektedir.