Proxy Tasarım Deseni, bir sınıf, bu sınıf tarafından implemente edilen bir arayüz ve yine bu arayüzü implemente eden bir proxy nesnesinden oluşur.
Konuyu anlamak için bir örnek üzerinden gidelim:
public interface ICalculate
{
long CalculatePower(long Number, long Power);
}
public class Calculator : ICalculate
{
public long CalculatePower(long Number, long Power)
{
long total = 1;
for (long i = 0; i < Power; i++)
{
total *= Number;
}
return total;
}
}
Calculator adlı sınıf, içerisinde CalculatePower adlı bir metod barındırıyor. Bu metodun dönüş tipi long. Kendisine veren ilk sayı’nın, ikinci sayı üzerinden üssünü hesaplıyor. Ve bunları ICalculate adlı bir kontrat üzerinden yapıyor. Şimdi, bir konsol uygulamasında çalıştığımızı varsayarak, Üs alacağımız programımızı yazıyoruz:
private static void Main(string[] args)
{
Calculator calculator = new Calculator();
string s = calculator.CalculatePower(9999999, 9999999).ToString();
Console.WriteLine(s);
Console.ReadKey();
}
Çalıştırdığımızda elimize geçen çıktı:
7884275548148951423
Burada, işlemcimizin gücüne bağlı olarak istediğimiz cevap biraz gecikebilir. Cevabı beklerken müşteriye, herhangi bir problem olmadığını belirten bir mesaj göstermek istiyoruz. Peki bu mesajı nereden göstereceğiz ? Bu iş için en iyi çözüm olan proxy nesnemizin içinden. Şimdi de bu nesneyi oluşturalım:
public class CalculatorProxy : ICalculate
{
ICalculate _calculator = new Calculator();
public long CalculatePower(long Number, long Power)
{
Console.WriteLine(“Calculating…”);
return _calculator.CalculatePower(Number, Power);
}
}
Calculate sınıfı gibi ICalculate’i implemente eden CalculateProxy adlı sınıfımız, öncelikle Calculate sınıfının bir örneğini oluşturuyor. CalculatePower adlı metodumuzda konsola bir mesaj yazdırdıktan sonra gerçek nesnemizin içindeki CalculatePower metodunu çalıştırıyoruz. Sonucu görmek için konsol istemcisinin kodunu düzenleyelim:
private static void Main(string[] args)
{
CalculatorProxy calculator = new CalculatorProxy();
string s = calculator.CalculatePower(9999999, 9999999).ToString();
Console.WriteLine(s);
Console.ReadKey();
}
Çıktı:
Calculating…
7884275548148951423
Gördüğünüz gibi, oldukça basit bir vekil nesne oluşturduk ve İstemci ile gerçek nesnenin arasına girmiş olduk. Ve en önemlisi, bunu yaparken, gerçek nesnenin koduna müdahale etmedik.
Bilgisayarımızın işlem gücünü kısıtladığını, yani maaliyetinin yüksek olduğunu varsaydığımız bu işlemi cache’lemeye tabii tutarak maaliyetten kesinti yapmak istersek, bunu da proxy ile kolayca halledebiliriz. Bunun için, parametre ile aldığı değere göre cache’den veri getirme veya ekleme işlemi yapan CacheOperations adlı sınıfımızı kodlayalım(not: bu sınıfın kodunda, konumuzun ilgi alanına giren hiç bir şey yoktur. kendi cache mekanizmanızı kullanabilir veya bunu kullanarak zaman kazanabilirsiniz):
public class CacheOperations
{
public class CacheMathPower
{
public long Number;
public long Power;
public long Result;
}
public List Cache = new List();
public long? Get(long Number, long Power)
{
var q = from Cac in Cache
where ((CacheMathPower)Cac).Number.Equals(Number)
&& ((CacheMathPower)Cac).Power.Equals(Power)
select new
{
((CacheMathPower)Cac).Result
};
if (q.Count() == 0)
{
return null;
}
else
{
return long.Parse(q.ToList()[0].Result.ToString());
}
}
public void Add(CacheMathPower cacheMathPower)
{
Cache.Add(new CacheMathPower()
{
Number = cacheMathPower.Number,
Power = cacheMathPower.Power,
Result = cacheMathPower.Result
});
}
}
CalculatorProxy adlı sınıfımızı da aşağıdaki hale getiriyoruz:
public class CalculatorProxy : ICalculate
{
private ICalculate _calculator = new Calculator();
private CacheOperations Cache = new CacheOperations();
public long CalculatePower(long Number, long Power)
{
Console.WriteLine(“Calculating…”);
long? retVal = Cache.Get(Number, Power);
if (retVal != null)
{
Console.WriteLine(“brought from cache…”);
return retVal.Value;
}
else
{
retVal = _calculator.CalculatePower(Number, Power);
Cache.Add(new CacheOperations.CacheMathPower()
{
Number = Number,
Power = Power,
Result = retVal.Value
});
}
return retVal.Value;
}
}
Programımızı çalıştıran metodu aşağıdaki gibi düzenliyoruz ve sonucu görüyoruz:
private static void Main(string[] args)
{
CalculatorProxy calculator = new CalculatorProxy();
string s = calculator.CalculatePower(9999999, 9999999).ToString();
Console.WriteLine(s);
s = calculator.CalculatePower(9999999, 9999999).ToString();
Console.WriteLine(s);
Console.ReadKey();
}
Çıktı:
Calculating…
7884275548148951423
Calculating…
brought from the cache…
7884275548148951423
Kodumuz biraz büyüdü. Belki ilk etapta gereksiz gelecek bazı şeyler yaptık ama bu şekilde bir Araya Girme(Interception) mekanizması yazmış olduk ve yazılımımızı belli bir maliyetten kurtardık. Kısaca; Proxy Nesnesi, kullanacağımız sınıfa eklemeler yapmak istiyorsak ama koda sahip değilsek, işlem öncesinde, sonrasında ve hatta sırasında bir takım ek işlemler yapmak istiyorsak başvurmamız gereken tasarım desenidir.