Gerçek uygulamalar tek bir sınıftan oluşmaz. Bir sipariş müşteriye ve ürünlere, bir kütüphane kitaplara ve üyelere, bir takım oyunculara sahiptir. Bu hafta nesneler arasındaki has-a ilişkisini, kompozisyonu ve bir nesnenin başka nesnelere işi devretmesini (delegation) kullanacağız.
Bu bölümün kapsamı
NoteSınavda sorulur
nesnenin başka nesneyi tuttuğu has-a ilişkisi
koleksiyonun nesneleri değil referanslarını tutması
iç mutable koleksiyonu dışarı açmanın kapsüllemeyi delmesi
Bu başlıklar konunun devamıdır; ileride karşınıza çıkar ama bu derste ezberlemeniz beklenmiyor.
Bu davranış hangi nesnenin işi?
Bir sipariş, ürünlerinin fiyat kuralını kendisi yazmalı mı, yoksa ürüne mi sormalı? Kütüphane kitabın durumunu doğrudan mı değiştirmeli? İki soruda da cevap kodun çalışıp çalışmadığına bakarak bulunmaz; kuralın kime ait olduğuna bakarak bulunur.
Bir nesne başka nesneyi tutabilir
Order, bir Customer nesnesine sahiptir: Order has a Customer.
Kompozisyon ve has-a ilişkisi
NoteKompozisyon ve agregasyon terimleri
Bu derste kompozisyon sözcüğünü, nesneleri içererek/kullanarak davranış oluşturma biçimindeki geniş has-a yaklaşımı için kullanıyoruz. UML ve bazı kaynaklarda aggregation (agregasyon) ile composition (bileşim), parçanın yaşam döngüsünün bütüne ne ölçüde bağlı olduğuna göre ayrıca ayrılır. Bu ayrımı tanımanız yararlıdır; ancak bu hafta uygulama ve ölçme beklentimiz formal UML ayrımı değil, doğru nesne ilişkisi ve sorumluluk tasarımıdır.
Nesne koleksiyonu
_items, sayı listesi değil Product nesnelerine ait referansları tutar.
Kritik sentez: iç koleksiyonu dışarı açmak kapsüllemeyi delebilir
Şu tasarım ilk bakışta kullanışlı görünür:
class Order:def__init__(self):self.items = []def add_product(self, product):# burada tekrar, stok veya başka kurallar olabilirself.items.append(product)
Ama çağıran kod şunu yapabilir:
order.items.append(product)
Böylece add_product() içindeki bütün kontroller atlanır. Daha da önemlisi, items listesini doğrudan döndüren bir property de aynı liste nesnesine referans verirse sorun çözülmüş olmaz:
@propertydef items(self):returnself._items # dış kod yine append yapabilir
Dışarıya yalnızca okunabilir bir görünüm vermek istiyorsak örneğin:
@propertydef items(self):returntuple(self._items)
veya bağımsız sığ kopya gerekiyorsa:
returnself._items.copy()
kullanılabilir. Hangi yaklaşımın uygun olduğu arayüz sözleşmesine bağlıdır.
Important3. hafta + 8. hafta burada birleşiyor
Bu sorun iki önceki fikrin doğrudan birleşimidir: 3. haftada mutable nesnelerde aliasing gördük; 8. haftada durum değişimini kontrollü bir arayüzden geçirmek gerektiğini öğrendik. İç listeyi dışarı verdiğiniz anda dış kod aynı mutable nesneye referans alır ve sınıfın kontrol kapısını dolaşabilir.
Delegation: işi sahibine bırakmak
OrderLine, ürünün fiyatlandırma kuralını kopyalamaz; Product.price_for() davranışına delegasyon yapar.
ImportantDelegation mekanik bir kural değildir
Amaç “her çağrıyı başka nesneye devretmek” değil, davranışı kuralın gerçek sahibine yerleştirmektir. Basit ara toplamın OrderLine içinde kalması da bağlama göre makul olabilir.
Library her nesnenin iç durumunu doğrudan yönetirse hızla “her şeyi yapan” merkeze dönüşür. Book.borrow() ve Member.add_borrowed_book() gibi davranışlar kendi nesnelerine ait olabilir; Library işlemi koordine eder.
Nesne koleksiyonu
Çokluk ilişkisi ve koleksiyon seçimi
Tek nesne: order.customer
Çok sayıda nesne: order.lines
Bir-çok ilişkide liste veya sözlük seçimi kullanım biçimine göre yapılmalıdır. Üye numarasından doğrudan erişim gerekiyorsa sözlük doğal olabilir:
Tekrar kontrolü koleksiyonu yöneten sınıfın sorumluluğundadır.
Alıştırma — İlişkiyi belirle
Car–Engine, Order–Customer, Playlist–Song, Student–Course çiftlerinde ilişkinin has-a olup olmadığını ve hangi tarafın diğerini tutmasının makul olduğunu tartışın. Her ilişkiyi iki tarafta da saklamanın senkronizasyon maliyetini ayrıca düşünün.
Alıştırma — Nesne koleksiyonunu tamamla
self._players.append(player)
Küçük üretim görevi — Kütüphane modeli
Book, Member, Library sınıflarıyla küçük bir model kurun:
Kitap ISBN ile tanımlansın,
Aynı ISBN iki kez eklenemesin,
Üye numarası benzersiz olsun,
Library kitap ve üyeleri koleksiyonlarda tutsun,
Koleksiyonların mutable iç nesnelerini doğrudan dışarı vermesin,
Ödünç alma davranışının hangi sınıfa/sınıflara ait olduğuna gerekçeyle karar verin.
Çalışır kod teslimi: İki kitap ve iki üye ekleyin; tekrarlı ISBN ve üye numarası durumlarının hata verdiğini assert/try-except ile doğrulayın. Ayrıca dışarıya verdiğiniz koleksiyon görünümünün append() ile değiştirilemediğini veya değişikliğin iç koleksiyonu etkilemediğini gösterin.
Sınav provası
Önce kendi cevabını seç; sonra cevap anahtarında her şıkkın neden doğru veya yanlış olduğunu oku. Çeldiriciler uydurma değil, bu konuda gerçekten yapılan hatalardır. Sınav maddeleri de bu mantıkla yazılır.
A.Library her nesnenin iç durumunu doğrudan yönettiği için “her şeyi yapan” bir merkeze dönüşür
B. Sorun yoktur; koordinasyon sınıfı bütün kuralları taşımalıdır
C.borrowed_count bir sınıf niteliği olmalıdır
D. Bir metot iki farklı nesneyi parametre olarak alamaz
E.is_borrowed niteliği dışarıdan değiştirilemez
Madde 8. Yukarıdaki Library tasarımını düzeltmek için en uygun adım nedir?
A.Book ve Member sınıflarını kaldırıp her şeyi sözlükte tutmak
B.Book.borrow() ve Member.add_borrowed_book() davranışlarını tanımlayıp Librarynin yalnız işlemi koordine etmesini sağlamak
C.borrow_book metodunu modül düzeyinde bir fonksiyona taşımak
D. Bütün nitelikleri property yapmak
E.Library sınıfını Book ve Member sınıflarından türetmek
Madde 9. Üye numarasından doğrudan erişim gerekiyorsa Library._members hangi yapıda tutulmalıdır?
A. Demet; üye listesi değişmemelidir
B. Liste; sıra korunduğu için arama daha kolaydır
C. Sözlük; anahtar üye numarası, değer Member nesnesi olur ve arama listeyi taramadan yapılır
D. Küme; üyeler benzersiz olduğu için
E. Her üye için ayrı bir nitelik
Madde 10. Aşağıdaki add_member metodunda tekrar kontrolünün burada yapılması neyi gösterir?
def add_member(self, member):if member.member_id inself._members:raiseValueError("Aynı üye numarası zaten var")self._members[member.member_id] = member
A. Üye numarasının sınıf niteliği olması gerektiğini
B.raise yerine assert kullanılması gerektiğini
C.Member sınıfının __eq__ metodunun eksik olduğunu
D. Koleksiyonun bütünlüğünü korumak, koleksiyonu yöneten sınıfın sorumluluğudur
E. Sözlüğün aynı anahtarı iki kez kabul ettiğini
TipCevaplar ve gerekçeler
Madde 1 — Doğru: E. Kompozisyonda nesne kopyalanmaz; referans tutulur. Müşterinin durumu değişince sipariş üzerinden de yeni değer görülür.
A yanlış: Yazdırılan, sınıf adı değil nitelik değeridir.
B yanlış: Python argümanı kopyalamaz; aynı nesne paylaşılır.
C yanlış: Zincirleme nitelik erişimi geçerlidir.
D yanlış:name niteliği bir metne bağlıdır.
Madde 2 — Doğru: A._itemsProduct nesnelerine referans tutar; total() her nesnenin price niteliğini toplar.
B yanlış: Toplanan fiyatlardır, eleman sayısı değil.
C yanlış: Toplanan nesneler değil, product.price değerleridir.
D yanlış:total() bir sayı döndürür.
E yanlış: İki ürün gerçekten eklenmiştir.
Madde 3 — Doğru: B. Sınıfın kontrol kapısı dolaşılır. 3. haftadaki aliasing ile 8. haftadaki kontrollü arayüz fikri burada birleşir.
A yanlış: Doğrudan append çağrısı metodu hiç çalıştırmaz.
C yanlış: Ekleyebilir; sorun da budur.
D yanlış: Sıra bozulmaz; sorun kuralların atlanmasıdır.
E yanlış: Normal bir örnek niteliğidir ve erişilebilir.
Madde 4 — Doğru: C. Property yalnızca erişim biçimini değiştirir. Döndürülen nesne hâlâ sınıfın iç listesidir.
A yanlış: Böyle bir otomatik kopyalama yoktur.
B yanlış: Property dönen nesneyi dondurmaz.
D yanlış: Alt çizgi yalnız bir sözleşmedir; teknik engel değildir.
E yanlış: Setter atamayı düzenler; döndürülen liste üzerinden yapılan değişikliği engellemez.
Madde 5 — Doğru: D. Demet eleman eklemeye ve çıkarmaya izin vermez; çağıran içeriği okuyabilir ama koleksiyonu değiştiremez.
A yanlış: Yalnız sayıyı verir; içeriği okumaya izin vermez.
B yanlış: Bağımsız kopya verir ama yine değiştirilebilir bir liste döndürür; okunabilirlik sözleşmesini ifade etmez.
C yanlış: Aynı mutable listeyi verir; dış kod append yapabilir.
E yanlış: Listeyi boşaltır ve None döndürür.
Madde 6 — Doğru: E. Delegasyon, kuralı kopyalamak yerine sahibine yönlendirmektir. İndirim kuralı değişirse yalnız Product güncellenir.
A yanlış: Aralarında kalıtım değil, kompozisyon vardır.
B yanlış: Böyle bir kısıt yoktur.
C yanlış: Yazılabilir ve çalışır; sorun tasarımdadır.
D yanlış: Delegasyon mekanik bir kural değildir; basit ara toplam yerinde de kalabilir.
Madde 7 — Doğru: A.Book.borrow() ve Member.add_borrowed_book() gibi davranışlar kendi nesnelerine aittir; Library işlemi yalnız koordine etmelidir.
B yanlış: Kurallar sahibi nesnelerde dururken koordinasyon ayrı bir iştir.
C yanlış: Her üyenin kendi sayısı olmalıdır; sınıf niteliği yanlış olurdu.
D yanlış: Alabilir; sorun parametrelerde değil sorumluluk dağılımındadır.
E yanlış: Python’da değiştirilebilir; asıl sorun kuralın nerede durduğudur.
Madde 8 — Doğru: B. Her nesne kendi durumunun kurallarını korur; koordinasyon sınıfı sırayı yönetir.
A yanlış: Sorumluluk dağılımını büsbütün kaybettirir.
C yanlış: Aynı merkezî kural yığını bu kez fonksiyona taşınır.
D yanlış: Erişimi düzenler ama davranışın hangi nesneye ait olduğunu değiştirmez.
E yanlış: Kütüphane bir kitap ya da üye değildir; kalıtım yanlış modeldir.
Madde 9 — Doğru: C. Kullanım biçimi “numaradan nesneye erişim” ise sözlük bu işi doğrudan yapar.
A yanlış: Üye eklemek gerekir; demet buna izin vermez.
B yanlış: Her aramada listeyi baştan taramak gerekir.
D yanlış: Küme üyelik bilgisi verir ama numaradan nesneye erişim sağlamaz.
E yanlış: Üye sayısı önceden bilinmediği için uygulanabilir değildir.
Madde 10 — Doğru: D. Tek bir üyenin kendi numarasının benzersizliğini bilmesi mümkün değildir; bu kural topluluğu tutan yerde durur.
A yanlış: Numara her üyeye özgüdür.
B yanlış: Bu bir iş kuralıdır; raise uygundur.
C yanlış: Kontrol eşitliğe değil, anahtarın varlığına bakar.
E yanlış: Sözlük ikinci yazımda değeri sessizce ezer; bu kontrol onu engeller.
Tek sayfa özet
Gerçek sistemler nesnelerin işbirliğiyle kurulur.
Nesne koleksiyonları da nesnenin durumudur; kapsülleme ilkeleri onlara da uygulanır.
Mutable iç koleksiyonu dışarı açmak aliasing yoluyla invariant’ları deldirebilir.
Delegation, işi uygun sorumluluğa devretmektir.
Bir-çok ilişkilerde koleksiyon seçimi ve benzersizlik anahtarı kullanım ihtiyacına göre belirlenir.
Kalıtım tek yeniden kullanım mekanizması değildir.
Bu bölümün kazanımları
Bu bölümü bitiren öğrenci:
Bir nesnenin başka bir nesneyi tuttuğu has-a ilişkisini kurar.
Nesne koleksiyonunun nesnelerin kendisini değil referanslarını tuttuğunu belirler.
İç mutable koleksiyonu dışarı açmanın kapsüllemeyi deldiğini gösterir.
Okunabilir görünüm için demet veya kopya döndürme seçeneklerini karşılaştırır.