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.



    [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