ProgramlamaC++ Yazılım Mimarı

C++'de aggregrasyon (aggregation) ve kompozisyon (composition) nedir? Birbirlerinden nasıl fark edilir ve hangi yaklaşım ne zaman kullanılmalıdır?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap.

C++ programlamasında, nesneleri birleştirmek için sıkça iki yöntem kullanılır: aggregasyon ve kompozisyon. Bu kavramlar, sınıflar arasındaki farklı ilişkileri yansıtır ve ilişkili nesnelerin yaşam döngüsünü ve yok etme sorumluluğunu etkiler.

Sorunun Tarihi:

Nesne yönelimli tasarımda nesneler arasındaki bağımlılıkları ayırmak her zaman önemli olmuştur. Nesne tabanlı dillerin (Smalltalk, C++, Java) ortaya çıkmasıyla birlikte, "kısım - bütün" ilişkilerini en iyi nasıl modelleyeceğine dair bir soru gündeme gelmiştir. C++'de bu, bellek ve nesnelerin yaşam döngüsü üzerinde manuel kontrol nedeniyle özellikle önemlidir.

Sorun:

Agregasyon ve kompozisyon arasındaki yanlış seçim, bellek sızıntılarına, kaynakların çoğaltılmasına veya nesnelerin yıkımıyla ilgili hatalara yol açabilir. Ayrıca, bu kavramlar sıkça karıştırılır.

Çözüm:

  • Kompozisyon — bir nesnenin bir kısım-nesneye sahip olduğu ve onun oluşturulmasından/yok edilmesinden sorumlu olduğu bir ilişkidir. C++'de bu genellikle bir değer sınıfı üyesi veya unique_ptr aracılığıyla ifade edilir.
  • Ağregasyon — kısım-nesnenin "bütün" dışında var olduğu ve onun yaşam döngüsünden sahibinin sorumlu olmadığı daha zayıf bir ilişkidir. Genellikle sahip olmayan bir referans (pointer/reference) aracılığıyla uygulanır.

Kod örneği:

// Kompozisyon: class Engine {}; class Car { Engine engine; // Engine, Car ile birlikte oluşturulur ve yok edilir }; // Ağregasyon: class Person {}; class Team { std::vector<Person*> members; // Person nesnelerine işaret eder, onlara sahip değildir };

Anahtar özellikler:

  • Kompozisyon — güçlü bir ilişki (part-of), sahiptir
  • Ağregasyon — zayıf bir ilişki (uses), sahip değildir
  • Kompozisyon bellek yönetimini otomatikleştirirken, agregasyon dikkat ve sahiplik anlaşmaları gerektirir.

Kandırıcı Sorular.

Eğer bir sınıf üyesinde bir nesneye işaret eden bir pointer varsa, bu her zaman agregasyon mudur?

Hayır! Eğer sınıf bu pointer üzerinde sahiplik taşırsa (örneğin, std::unique_ptr aracılığıyla), bu yine kompozisyondur. İlişki türü, alanın türünden değil, yaşam döngüsündeki sorumluluktan belirlenir.

class House { std::unique_ptr<Room> room; // kompozisyon, House Room'a sahiptir };

Kompozisyon, referans veya raw pointer aracılığıyla uygulanabilir mi?

Uygulanabilir — ancak yalnızca nesne sahibi tarafından oluşturulup yok ediliyorsa ve referans veya pointer optimizasyon için kullanılıyorsa. Ancak sahipliği açıkça ifade etmek için değer nesneleri veya akıllı pointer'lar kullanmak çok daha iyidir.

Eğer kompozisyondaki kısım-nesne sahibi dışında oluşturulup kendisine verilirse ne olur?

Bu durumda kompozisyonun invariyantlarının ihlal edilme riski vardır: eğer dışarıda oluşturulan nesne sahibine verilirse ve o nesneyi yok ederse, başka bir yerde ona referans varsa, dangling pointer oluşur. Projede sahiplik ve yok etme sorumluluklarını net bir şekilde tanımlamak gereklidir.

Yaygın Hatalar ve Anti-Paternler

  • Agregasyon ve kompozisyon kavramlarını karıştırmak (örneğin, gereksiz raw pointer'lar tutmak ancak onları sahibinin yıkıcısında yok etmeye çalışmak)
  • Sıkı bir yaşam döngüsünün gerekli olduğu yerlerde agregasyon kullanmak (örneğin, karmaşık bir nesnenin detayları)
  • Sahip olmayan pointer'ları serbest bırakmamak

Gerçek Hayattan Bir Örnek

Negatif Durum

Bir ekip, tüm yerleşik nesneleri raw pointer'lar aracılığıyla bir konteynerde tutmaya ve yıkıcıda manuel olarak onları yok etmeye karar verdi. Her şey çalışıyordu, ta ki sahiplik şemasını değiştirdiklerinde. Sonuç olarak, pointer iki kez serbest bırakıldı ve bir çökme meydana geldi.

Artılar:

  • Bazı durumlar için mimaride esneklik (örneğin, nesneler arasındaki yüzdeli ilişkiler)

Eksiler:

  • Bellek yönetiminde yüksek hata riski
  • Bakımı zor

Pozitif Durum

Başka bir ekip, gerçekten sahiplik ilişkileri için std::unique_ptr kullanmaya geçti ve sahip olmayanları yalnızca geçici referanslar biçiminde kullandı. Bu, mimariyi açıkça ifade etti.

Artılar:

  • Şeffaf ve anlaşılır sahiplik ilişkileri
  • Bellek sızıntısı veya çift serbest bırakma yok

Eksiler:

  • Her zaman döngüsel kompozisyon mümkün değildir
  • Bazen nesneler arasındaki iletişim protokollerinin revize edilmesi gerekir