Twin Design Pattern(İkiz Tasarım Deseni)
Merhaba,
Bu içeriğimizde çoklu kalıtımı desteklemeyen C#, Java vs. gibi dillerde çoklu kalıtımı simüle etmemizi sağlayan Twin Design Pattern(İkiz Tasarım Deseni)’ı inceliyor olacağız.
Twin Pattern, yukarıdaki giriş cümlesinde de bahsedildiği üzere çoklu kalıtımı simüle edebilmek için standart bir çözüm sunan bir modeldir. Bu pattern sayesinde çoklu kalıtım ile ilgili isim çakışmaları(name clashes) sorunlarından kaçınılabilmekte ve ortaya koyduğu mantık ile çoklu kalıtımın getirdiği olası birçok sorun önlenebilmektedir.
Çoklu kalıtım(multiple inheritance), bir class’ın birden fazla base class’ı olması anlamına gelmektedir. Kimi programcılar açısından olmazsa olmaz bir özellik olarak iddia ediliyor olsa da isim çatışmalarına(name clashes), karmaşıklığa(complexity) ve tüm bunlar neticesinde verimsizliğe(inefficiency) yol açtığı için genel kanı olarak sorunlara kaynak teşkil etmekte ve bundan dolayı olumsuz bir nitelik olarak değerlendirilmektedir. Haliyle bu yüzden C# ve Java gibi dillerde çoklu kalıtım dilin doğasında engellenmiştir. Böylece zoraki olarak çoklu kalıtımdan arındırılmış kod yapısı sayesinde yazılım mimarileri doğal olarak daha temiz ve basit hale gelmiş bulunmaktadır.
Şimdi gelin, çoklu kalıtımın davranışsal yapısıyla Twin pattern’ı mukayese edebilmek için diyagram şemaları üzerinden modelleyelim.
Yukarıdaki yaptığımız küçük örnek üzerinden dikkat ederseniz eğer Twin nesneler birbirlerine erişebildiklerinden dolayı client bu nesnelerden sadece birine doğrudan diğerine ise o nesne üzerinden dolaylı bir yoldan erişim sağlamaktadır.
Tabi bu pattern’ın tek sınırlılığı Twin nesnelerin, birbirlerine doğrudan olan erişimleri sebebiyle sıkı bir bağımlılıklarının olmasıdır. Haa bu bağımlılık neticesinde birbirlerinin memberlarını da gönül rahatlığıyla kullanabildiklerinden dolayı bu durum göz ardı edilebilmektedir.
Twin pattern, kalıtımdan daha az verimli ve performanslı olabilir. Ama ihtiyaca binaen kullanıldığı noktalarda bu durum gönül rahatlığıyla göz ardı edilebilir.
Gerçek Senaryo
Şimdi gelin içeriğimizi gerçek bir senaryoyla taçlandırarak, noktalayalım.
Kesme, boyut büyültme/küçültme, birleştirme vs. gibi türlü döküman işlemleri gerçekleştiren bir uygulama geliştirdiğimizi düşünelim. Bu uygulama içerisinde ‘PDF’ ve ‘Excel’ operasyonları gerçekleştirmek için hali hazırda gelen ‘PDFOperation’ ve ‘ExcelOperation’ sınıflarının olduğunu varsayalım. Bizler ihtiyaç olarak her iki sınıftan da özellik ve fonksiyonellikleri alarak, bünyesinde toplayan ve bütünsel olarak işlem yapmamızı sağlayacak olan bir sınıfa odaklanacağız ve bu ihtiyacı Twin pattern ile sağlıyor olacağız.
- Adım 1
İlk olarak memberları alınacak olan ‘PDFOperation’ ve ‘ExcelOperation’ sınıflarını sembolik olarak temsil ederek başlayalım:
‘PDFOperation’;public class PDFOperation : IOperation { public object Convert(object file) { Console.WriteLine($"{nameof(PDFOperation)}.{nameof(PDFOperation.Convert)} fonksiyonu."); //... Convert operasyonu ... return file; } public object Merge(object[] files) { Console.WriteLine($"{nameof(PDFOperation)}.{nameof(PDFOperation.Merge)} fonksiyonu."); //... Merge operasyonu ... return files; } public object SizeEnlargement(object file) { Console.WriteLine($"{nameof(PDFOperation)}.{nameof(PDFOperation.SizeEnlargement)} fonksiyonu."); //... SizeEnlargement operasyonu ... return file; } public object SizeReduction(object file) { Console.WriteLine($"{nameof(PDFOperation)}.{nameof(PDFOperation.SizeReduction)} fonksiyonu."); //... SizeReduction operasyonu ... return file; } public object Splitting(object file) { Console.WriteLine($"{nameof(PDFOperation)}.{nameof(PDFOperation.Splitting)} fonksiyonu."); //... Splitting operasyonu ... return file; } }
‘ExcelOperation’;
public class ExcelOperation : IOperation { public object Convert(object file) { Console.WriteLine($"{nameof(ExcelOperation)}.{nameof(ExcelOperation.Convert)} fonksiyonu."); //... Convert operasyonu ... return file; } public object Merge(object[] files) { Console.WriteLine($"{nameof(ExcelOperation)}.{nameof(ExcelOperation.Merge)} fonksiyonu."); //... Merge operasyonu ... return files; } public object SizeEnlargement(object file) { Console.WriteLine($"{nameof(ExcelOperation)}.{nameof(ExcelOperation.SizeEnlargement)} fonksiyonu."); //... SizeEnlargement operasyonu ... return file; } public object SizeReduction(object file) { Console.WriteLine($"{nameof(ExcelOperation)}.{nameof(ExcelOperation.SizeReduction)} fonksiyonu."); //... SizeReduction operasyonu ... return file; } public object Splitting(object file) { Console.WriteLine($"{nameof(ExcelOperation)}.{nameof(ExcelOperation.Splitting)} fonksiyonu."); //... Splitting operasyonu ... return file; } }
Tabi normal şartlarda bu sınıflar kullanılan kütüphane/dll üzerinden geleceklerdir. Zaten kaynak kodu elimizde olmayan ya da kaynak kodunu bozmak istemediğimiz sınıflarda çoklu kalıtım senaryolarını uygulayabilmek için Twin pattern kullanılmaktadır. Aksi taktirde ilgili sınıfların kaynakları bizdeyse ve erişilebilir bir vaziyetteyse yahut gönül rahatlığıyla değişiklik yapabiliyorsak direkt olarak ilgili sınıflarda birbirlerini referans verdirebilir yahut birine diğerinden kalıtım aldırarak meseleyi çözebilirdik.
- Adım 2
Ardından bu sınıflardan kalıtım alan ve biryandan da birbirlerini refere eden child sınıfları oluşturalım:
‘ChildPDFOperation’;public class ChildPDFOperation : PDFOperation { public ChildExcelOperation Excel { get; set; } public bool SendMail(object file) { //... SendMail operasyonu .... return true; } }
‘ChildExcelOperation’;
public class ChildExcelOperation : ExcelOperation { public ChildPDFOperation PDF { get; set; } }
Tabi ki de bu sınıflar kendi içlerinde özel memberlar da barındırabilmektedirler.
- Adım 3
Ve son olarak child sınıflardan herhangi birini kullanarak hem PDF hem de Excel operasyonlarını tek nesne üzerinden gönül rahatlığıyla yürütelim.ChildPDFOperation pdf = new(); pdf.Excel = new(); pdf.Convert(null); pdf.Excel.Merge(null);
Görüldüğü üzere böylece çoklu kalıtım senaryosu başarıyla uygulanmıştır.
Nihai olarak, basit ama ihtiyaç doğrultusunda oldukça etkili olan bir pattern’ı örnekler eşliğinde incelemiş olduk.
Sabırla eşlik ettiğiniz için teşekkür ederim.
İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…
Not : Kaynak kodları aşağıdaki Github adresinden edinebilirsiniz.
https://github.com/gncyyldz/TwinDesignPattern