Creational — Oluşturucu Desenler
Prototype
Prototip (Klonlama) Deseni
Amaç: Yeni nesneleri sıfırdan oluşturmak yerine, mevcut bir nesneyi (prototipi) kopyalayarak üretmek.
Basit Anlatım
Teknik terim yok — günlük hayattan bir benzetme
Bir dilekçe yazdınız: başlık, adres, tarih, imza alanı, güzel bir yazı tipiyle hazırladınız. Şimdi aynı dilekçeden başka bir kurum için de lazım.
Her şeyi sıfırdan yazmak yerine ne yaparsınız? Fotokopisini çekersiniz ve yalnızca kurum adını değiştirirsiniz. Çok daha hızlıdır.
Doğadan bir örnek
Hücreler bölünerek çoğalır. Yeni hücre, ana hücrenin bir kopyasıdır; doğa her hücreyi sıfırdan tasarlamaz.
Dikkat: Yüzeysel kopya tuzağı
Diyelim ki dilekçenin yanına bir klasör iliştirdiniz. Fotokopi çektiğinizde klasörün kendisi kopyalanmaz, sadece "ekte klasör var" yazısı kopyalanır. İki dilekçe aynı klasörü paylaşıyor olur; birine belge eklerseniz diğerinde de görünür. Gerçek bir kopya için klasörü de ayrıca çoğaltmanız gerekir.
Teknik Anlamı
Bir yazılımcının bakış açısıyla
Prototype, nesnelerin kendilerini klonlamasını sağlayan bir Clone() metodu tanımlar. İstemci, nesnenin somut sınıfını bilmeden kopyasını üretebilir.
Ne zaman kullanılır?
- Nesne oluşturmak pahalıysa (veritabanı sorgusu, ağ çağrısı, ağır hesaplama).
- Çok sayıda benzer nesne gerekiyorsa ve aralarındaki fark küçükse.
- Somut sınıfı bilmeden bir nesnenin kopyasına ihtiyaç varsa.
Shallow copy vs Deep copy
- Shallow (yüzeysel) kopya: Değer tipleri kopyalanır, referans tipleri ise aynı nesneyi gösterir. .NET'te
MemberwiseClone()bunu yapar. - Deep (derin) kopya: Referans edilen nesneler de kopyalanır; kopya ile orijinal tamamen bağımsızdır.
.NET'te Prototype
ICloneablearayüzü vardır ancak shallow mı deep mi olduğunu belirtmediği için Microsoft tarafından önerilmez. Kendi tipli arayüzünüzü yazmak daha iyidir.- C#
recordtipleri vewithifadesi yerleşik bir prototip mekanizmasıdır:var b = a with { Name = "x" };(ancak bu da shallow kopyadır).
Avantajlar
- Pahalı başlatma işlemleri tekrarlanmaz.
- Karmaşık nesneler için önceden yapılandırılmış "şablonlar" tutulabilir.
Dezavantajlar
- Döngüsel referansları olan nesnelerde deep copy yazmak zordur.
C# ile Uygulama
Adım adım, çalışan kod örneği
Senaryo: Bir oyunda düşman karakterleri. Her düşmanı sıfırdan yapılandırmak yerine hazır şablonları kopyalıyoruz. Shallow ve deep copy farkını da göstereceğiz.
Adım 1 Prototip arayüzü ve referans tipli bir alan
public interface IPrototype<T>
{
T ShallowClone();
T DeepClone();
}
public class Equipment
{
public List<string> Items { get; set; } = new();
}Adım 2 Klonlanabilir sınıf
MemberwiseClone() alanları birebir kopyalar. Deep copy için referans tipli Equipment nesnesini de elle kopyalıyoruz.
public class Enemy : IPrototype<Enemy>
{
public string Name { get; set; } = "";
public int Health { get; set; }
public Equipment Gear { get; set; } = new();
public Enemy ShallowClone() => (Enemy)MemberwiseClone();
public Enemy DeepClone()
{
var copy = (Enemy)MemberwiseClone();
copy.Gear = new Equipment { Items = new List<string>(Gear.Items) };
return copy;
}
public override string ToString() =>
$"{Name,-14} Can: {Health,3} Ekipman: {string.Join(", ", Gear.Items)}";
}Adım 3 Prototip kayıt defteri (registry)
Hazır şablonları isimle saklayıp istendiğinde kopyasını veren yardımcı sınıf.
public class EnemyRegistry
{
private readonly Dictionary<string, Enemy> _prototypes = new();
public void Register(string key, Enemy prototype) => _prototypes[key] = prototype;
public Enemy Spawn(string key) => _prototypes[key].DeepClone();
}Adım 4 Kullanım
Tüm parçaları bir araya getiren istemci (client) kodu:
var orcTemplate = new Enemy
{
Name = "Ork Savaşçı", Health = 120,
Gear = new Equipment { Items = { "Balta", "Kalkan" } }
};
var registry = new EnemyRegistry();
registry.Register("ork", orcTemplate);
var orc1 = registry.Spawn("ork");
var orc2 = registry.Spawn("ork");
orc2.Name = "Ork Lideri";
orc2.Health = 200;
orc2.Gear.Items.Add("Miğfer");
Console.WriteLine(orc1);
Console.WriteLine(orc2);
Console.WriteLine("\n--- Shallow copy tuzağı ---");
var shallow = orcTemplate.ShallowClone();
shallow.Gear.Items.Add("Zehirli Hançer");
Console.WriteLine($"Şablon : {orcTemplate}");
Console.WriteLine($"Kopya : {shallow}");
Console.WriteLine($"Aynı ekipman nesnesi mi? {ReferenceEquals(shallow.Gear, orcTemplate.Gear)}");Konsol çıktısı
Ork Savaşçı Can: 120 Ekipman: Balta, Kalkan Ork Lideri Can: 200 Ekipman: Balta, Kalkan, Miğfer --- Shallow copy tuzağı --- Şablon : Ork Savaşçı Can: 120 Ekipman: Balta, Kalkan, Zehirli Hançer Kopya : Ork Savaşçı Can: 120 Ekipman: Balta, Kalkan, Zehirli Hançer Aynı ekipman nesnesi mi? True
Kodda dikkat edilmesi gerekenler
orc2'ye eklenen "Miğfer"orc1'de görünmüyor çünküSpawndeep copy yapıyor.- Shallow kopyaya eklenen "Zehirli Hançer" şablonu da bozdu; çünkü iki nesne aynı
Equipmentörneğini paylaşıyor. Prototype kullanırken en sık yapılan hata budur.