C# Prototype Pattern Kullanımı - OOP Design Patterns
Büyük,karmaşık,resource kullanımı oldukça fazla olan nesneler ile çalışıyorsak bu nesneleri defalarca new ile yeniden yaratma maliyeti çok fazla ise, nesneler arası alanların kopyalanması gerekiyorsa faydalı olabilecek bir pattern Prototype.
Neden önemli bu pattern çünkü bir uygulama geliştirirken maliyetler çok önemli,nesnelerin üretilme maliyeti de tabii ki öyle. İşte Prototype pattern ile nesnenin tipinin ne olduğunu bilmeden elimizdeki bir nesnenin kopyasını alabiliyoruz.
Bu pattern'i işlerken 2 farklı nesne kopyalama yöntemini inceleyeceğiz: Shallow Copy, Deep Copy.
Shallow Copy:
Nesnenin üye elemanlarını kopyalar. Eğer bu üye eleman Değer tipinde ise bit bit kopyalama işlemi gerçekleştirilir. Eğer üye eleman referans tipinde ise referans kopyalanır fakat referansın gösterdiği veri kümesi kopyalanmaz. Orjinal nesne ve Kopyalanmış nesnede yer alan referans tipi üye eleman bellekte aynı veri kümesine işaret eder. Kopyalama işlemi static üye elemanları için geçersizdir.
Deep Copy:
Nesnenin bütün değer ve referans üye elemanlarını bit bit kopyalama işlemine denir. Deep copy işlemini kendimiz yazmamız gerekmektedir. Deep copy için .Net in sunduğu herhangi bir sınıf metod bulunmamaktadır.
Şimdi örnek programımızı yazalım. Önce IPrototype abstract sınıfımızı yazalım. Bu sınıfı sizde projelerinize ekleyerek Shallow ve Deep copy yapabilirsiniz.
Ardından Employee ve Company sınıflarımızı yazalım. Burda önemli bir nokta Deep Copy yapılabilmesi için bu sınıfların Serializable olması gerektiğidir.
Ardından Shallow Copy örneğimizi yapalım:
Çıktı:
Çıktıda kırmızı ile işaretlediğim kısım önemli. Kopyalamanın ardından nesnenin alt nesneleri arasında değişiklik yapıldığında kopyalanan nesnede etkilenir. Örneğimizde sadece e2 nesnesinin e2.Company.Name alanı DEF Company yapılmasına rağmen e1 inde değişmiştir. Çünkü refaranslar kopyalanmıştır. Her ikiside aynı referans adresine bakmaktadır.
Şimdi Deep Copy örneğimizi yapalım:
Çıktı:
Deep copy nesnenin bütün değer ve referans üye elemanlarını bit bit kopyalama işlemi yaptığı için çıktıdan açıkça görebileceğiniz gibi, bu sefer e2.Company.Name yine DEF Company yapıldığı halde e1 in Company.Name bilgisi değişmemiştir.
Neden önemli bu pattern çünkü bir uygulama geliştirirken maliyetler çok önemli,nesnelerin üretilme maliyeti de tabii ki öyle. İşte Prototype pattern ile nesnenin tipinin ne olduğunu bilmeden elimizdeki bir nesnenin kopyasını alabiliyoruz.
Bu pattern'i işlerken 2 farklı nesne kopyalama yöntemini inceleyeceğiz: Shallow Copy, Deep Copy.
Shallow Copy:
Nesnenin üye elemanlarını kopyalar. Eğer bu üye eleman Değer tipinde ise bit bit kopyalama işlemi gerçekleştirilir. Eğer üye eleman referans tipinde ise referans kopyalanır fakat referansın gösterdiği veri kümesi kopyalanmaz. Orjinal nesne ve Kopyalanmış nesnede yer alan referans tipi üye eleman bellekte aynı veri kümesine işaret eder. Kopyalama işlemi static üye elemanları için geçersizdir.
Deep Copy:
Nesnenin bütün değer ve referans üye elemanlarını bit bit kopyalama işlemine denir. Deep copy işlemini kendimiz yazmamız gerekmektedir. Deep copy için .Net in sunduğu herhangi bir sınıf metod bulunmamaktadır.
Şimdi örnek programımızı yazalım. Önce IPrototype abstract sınıfımızı yazalım. Bu sınıfı sizde projelerinize ekleyerek Shallow ve Deep copy yapabilirsiniz.
[Serializable]
public abstract class IPrototype<T>
{
//
Shallow copy
public T Clone()
{
return (T)this.MemberwiseClone();
}
// Deep
Copy
public T DeepCopy()
{
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Seek(0, SeekOrigin.Begin);
T copy =
(T)formatter.Deserialize(stream);
stream.Close();
return copy;
}
}
Ardından Employee ve Company sınıflarımızı yazalım. Burda önemli bir nokta Deep Copy yapılabilmesi için bu sınıfların Serializable olması gerektiğidir.
[Serializable]
public class Company
{
public string Name { get; set; }
}
[Serializable]
public class Employee: IPrototype<Employee>
{
public string FullName { get; set; }
public int EmployeeId { get; set; }
public Company Company { get; set; }
}
Ardından Shallow Copy örneğimizi yapalım:
class Program
{
static void Main(string[] args)
{
//Shallow
Copy
//Employee
Create : e1
Console.WriteLine("Shallow
Copy");
Console.WriteLine();
Employee e1 = new Employee() { FullName = "Osman", EmployeeId = 1 };
e1.Company = new Company() { Name = "ABC Company" };
Console.WriteLine("After e1
Create:");
Console.WriteLine();
//Print
e1 Employee Info
PrintEmployee(e1, "e1");
//
Shallow Copy e1 to e2
Employee e2 = e1.Clone();
Console.WriteLine("After e1 to
e2 Shallow Copy:");
Console.WriteLine();
//Print
e2 Employee Info // All fields same as e1
PrintEmployee(e2, "e2");
//Altered
Clone's shallow state, prototype unaffected
e2.FullName = "Ahmet";
//Altered
Clone's shallow state, prototype unaffected
e2.EmployeeId = 2;
//!!!IMPORTANT:
Altering Clone deep state: prototype affected. Now e1.Company.Name has changed.
e2.Company.Name = "DEF Company";
Console.WriteLine("After
Change:");
Console.WriteLine();
//Print
e1 Employee Info
PrintEmployee(e1, "e1");
//Print
e2 Employee Info
PrintEmployee(e2, "e2");
Console.ReadLine();
}
Çıktı:
Çıktıda kırmızı ile işaretlediğim kısım önemli. Kopyalamanın ardından nesnenin alt nesneleri arasında değişiklik yapıldığında kopyalanan nesnede etkilenir. Örneğimizde sadece e2 nesnesinin e2.Company.Name alanı DEF Company yapılmasına rağmen e1 inde değişmiştir. Çünkü refaranslar kopyalanmıştır. Her ikiside aynı referans adresine bakmaktadır.
Şimdi Deep Copy örneğimizi yapalım:
#region Deep Copy
//Deep
Copy
//Employee
Create : e1
Console.WriteLine("Deep
Copy");
Console.WriteLine();
Employee e1 = new Employee() { FullName = "Osman", EmployeeId = 1 };
e1.Company = new Company() { Name = "ABC Company" };
Console.WriteLine("After e1
Create:");
Console.WriteLine();
//Print
e1 Employee Info
PrintEmployee(e1, "e1");
// Deep
Copy e1 to e2
Employee e2 = e1.DeepCopy();
Console.WriteLine("After e1 to
e2 Deep Copy:");
Console.WriteLine();
//Print
e2 Employee Info // All fields same as e1
PrintEmployee(e2, "e2");
//Altered
Clone's shallow state, prototype unaffected
e2.FullName = "Ahmet";
//Altered
Clone's shallow state, prototype unaffected
e2.EmployeeId = 2;
//!!!IMPORTANT:
Altering Clone deep state: prototype affected. Now e1.Company.Name has changed.
e2.Company.Name = "DEF Company";
Console.WriteLine("After
Change:");
Console.WriteLine();
//Print
e1 Employee Info
PrintEmployee(e1, "e1");
//Print
e2 Employee Info
PrintEmployee(e2, "e2");
Console.ReadLine();
#endregion
Çıktı:
Deep copy nesnenin bütün değer ve referans üye elemanlarını bit bit kopyalama işlemi yaptığı için çıktıdan açıkça görebileceğiniz gibi, bu sefer e2.Company.Name yine DEF Company yapıldığı halde e1 in Company.Name bilgisi değişmemiştir.
0 yorum :
Yorum Gönder