Ders 16 / 18
Nesneye Dayalı Programlamaya Giriş
Veri ile davranışın birleşmesi, sınıf ve nesne, kapsülleme, değişmezlerin korunması ve arayüz fikri.
İçindekiler
Önceki ders iki zorlukla bitti: bir veri yapısının hangi yordamlara ait olduğu kodda yazılı değildir, ve veri yapısının kuralları her kullanan yordamda ayrı ayrı korunmak zorundadır.
Nesneye dayalı programlama, her iki zorluğa aynı hamleyle yanıt verir: veriyi ve onu işleyen davranışı tek bir birimde toplar. Bu birime nesne denir.
Sınıf ve Nesne
Sınıf, bir nesne türünün tanımıdır: hangi verileri taşıyacağını ve hangi işlemleri destekleyeceğini söyler. Nesne, o tanımdan üretilmiş somut bir örnektir.
Ayrım, tip ile değer arasındaki ayrımın aynısıdır: sınıf kalıp, nesne o kalıptan
üretilmiş bireydir. Tek bir ÖlçümSerisi sınıfından, birbirinden bağımsız yüzlerce
ölçüm serisi nesnesi üretilebilir; her birinin kendi verisi vardır, davranışları ortaktır.
class OlcumSerisi: """Bir ölçüm dizisini ve üzerindeki işlemleri birlikte taşır.""" def __init__(self, olcumler: list[int]) -> None: if not olcumler: raise ValueError("ölçüm listesi boş olamaz") self._olcumler = list(olcumler) # savunma kopyası def ekle(self, olcum: int) -> None: self._olcumler.append(olcum) def ortalama(self) -> float: return sum(self._olcumler) / len(self._olcumler) def en_buyuk(self) -> int: en_buyuk = self._olcumler[0] for olcum in self._olcumler: if olcum > en_buyuk: en_buyuk = olcum return en_buyuk def sayi(self) -> int: return len(self._olcumler) seri = OlcumSerisi([12, 18, 7, 25, 14]) print(seri.ortalama(), seri.en_buyuk(), seri.sayi()) # 15.2 25 5 seri.ekle(30) print(seri.ortalama(), seri.en_buyuk()) # 17.666666666666668 30
Yapısal çözümde ayrı ayrı duran topla, en_buyugu_bul ve veri, burada tek bir birimde
toplanmıştır. Çağrı biçimi de değişmiştir: yordama veri verilmez, nesneye mesaj gönderilir.
Kapsülleme ve Değişmezler
Nesnenin verisi, dışarıdan doğrudan erişime kapatılır; erişim yalnızca nesnenin sunduğu işlemler üzerinden yapılır. Buna kapsülleme denir.
Kapsüllemenin gerekçesi gizlilik değil, değişmezlerin korunmasıdır. OlcumSerisi
sınıfının değişmezi şudur: ölçüm listesi hiçbir zaman boş değildir. Bu kural iki yerde
korunur — yaratımda denetlenir, ve listeyi boşaltacak bir işlem sunulmaz.
Yapısal çözümde aynı kuralı korumak, listeyi kullanan her yordamda ayrı bir denetim gerektiriyordu. Burada kural tek bir yerde, verinin sahibinde durur.
Bu, önceki konudaki savunma kopyası tartışmasının da devamıdır: yapıcıda kopya alınmasaydı, dışarıdaki liste değiştirilerek değişmez çiğnenebilirdi. Dışarı veri döndüren bir işlem eklenseydi, aynı gerekçeyle kopya döndürmesi gerekirdi.
Arayüz ve Gerçekleştirim
Nesnenin dışarıya sunduğu işlemler kümesine arayüz, bu işlemlerin nasıl yapıldığına gerçekleştirim denir. Çağıran yalnızca arayüzü bilir.
Ayrımın değeri, gerçekleştirimin serbestçe değiştirilebilmesidir. OlcumSerisi, en
büyük değeri her çağrıda baştan hesaplamak yerine ekleme sırasında güncelleyerek
saklayabilir; arayüz aynı kaldığı için çağıran koddan hiçbir satır değişmez.
Bu, yapısal ayrıştırmadaki bilgi saklama fikrinin daha güçlü biçimidir: orada yordamın içi gizliydi, burada verinin temsili de gizlidir.
Nesneler Arası İlişki
Tek bir nesne nadiren yeterlidir; program, birbirine mesaj gönderen nesneler ağı olarak kurulur. İlişkilerin iki temel biçimi vardır.
Bileşim, bir nesnenin başka bir nesneyi parçası olarak taşımasıdır. Ölçüm serisini saklayan bir rapor nesnesi, seriyi kendi içinde tutar ve ömrünü yönetir.
İşbirliği, bir nesnenin başka bir nesneyi tanıyıp ona mesaj göndermesidir; ikisi bağımsız yaşar.
class Rapor: """Bir ölçüm serisinden okunabilir özet üretir.""" def __init__(self, seri: OlcumSerisi) -> None: self._seri = seri # işbirliği: seri dışarıda yaratıldı def metin(self) -> str: return (f"{self._seri.sayi()} ölçüm, " f"ortalama {self._seri.ortalama():.1f}, " f"en büyük {self._seri.en_buyuk()}") seri = OlcumSerisi([12, 18, 7, 25, 14]) print(Rapor(seri).metin()) # 5 ölçüm, ortalama 15.2, en büyük 25
Rapor sınıfı, serinin içini bilmez; yalnızca arayüzünü kullanır. Bu, önceki bölümdeki
arayüz–gerçekleştirim ayrımının nesneler arası karşılığıdır ve tasarımın belirleyici
ölçütünü verir: bir nesne, başka bir nesnenin iç yapısına ne kadar az bağlıysa
değişiklik o kadar az yayılır.
Bağımlılığın yönü de bir karardır. Burada rapor seriye bağlıdır, seri rapordan habersizdir; bu nedenle yeni bir rapor biçimi eklemek seriyi hiç değiştirmez. Ters yönde bir bağımlılık kurulsaydı, her yeni rapor türü seriyi de değiştirmeyi gerektirirdi.
Kalıtım ve Çok Biçimlilik
İki kavram daha bu yaklaşımın parçasıdır ve burada yalnızca tanıtılır.
Kalıtım, bir sınıfın başka bir sınıfın tanımını genişletmesidir. Ortak davranış üst sınıfta bir kez yazılır, alt sınıflar farklılıkları ekler.
Çok biçimlilik, aynı mesajın farklı nesne türlerinde farklı davranmasıdır. Çağıran, karşısındaki nesnenin tam türünü bilmeden aynı işlemi çağırabilir; hangi gerçekleştirimin çalışacağına nesne karar verir.
Çok biçimliliğin pratik sonucu, koşul zincirlerinin ortadan kalkmasıdır: “türe göre farklı
davran” mantığı, if zinciri yerine ayrı sınıflara dağıtılır. Koşullu dallanma dersindeki
eşleme tablosu yaklaşımının nesneye dayalı karşılığı budur.
İkisinin doğru kullanımı — özellikle kalıtımın ne zaman bileşime tercih edileceği — Yazılım Tasarımı ve Mimari İlkeler müfredatının konusudur.
Kimlik ve Eşitlik
Nesneler durum taşıdığı için, “aynı” sözcüğü iki anlama gelir. Değişkenler dersindeki kimlik–eşitlik ayrımı burada tasarım kararına dönüşür.
İki ölçüm serisi aynı değerleri taşıyorsa eşit sayılmalı mıdır, yoksa yalnızca aynı nesne oldukları durumda mı? Yanıt, nesnenin neyi temsil ettiğine bağlıdır.
Değer nesneleri — bir tarih, bir para tutarı, bir koordinat — içerikleriyle tanımlanır; aynı içeriğe sahip iki örnek eşittir ve genellikle değiştirilemez yapılır.
Varlık nesneleri — bir kullanıcı hesabı, bir sipariş — kimlikleriyle tanımlanır. İki hesabın tüm alanları aynı olsa bile farklı hesaplardır; ayırt edici olan kimliktir.
Bu ayrım yapılmadığında, koleksiyonlarda arama ve karşılaştırma beklenmedik sonuç verir. Diller genellikle eşitlik davranışının sınıf tarafından tanımlanmasına izin verir; bu tanım yazılmazsa varsayılan kimlik karşılaştırmasıdır.
Değer ve varlık nesnelerinin ayrımı, alan odaklı tasarımın temel kavramlarındandır ve Yazılım Tasarımı ve Mimari İlkeler müfredatında genişletilir.
Ne Zaman Uygun, Ne Zaman Değil
Nesneye dayalı düzenleme, problemin doğal olarak durumu olan varlıklar içerdiği yerlerde güçlüdür: bir hesap, bir bağlantı, bir belge, bir oyun karakteri. Bu varlıkların kuralları vardır ve kurallar veriyle birlikte durmalıdır.
Buna karşılık, durum taşımayan saf dönüşümler için nesne kurmak gereksiz katman üretir. İki sayıyı toplayan bir işlem, sınıf gerektirmez.
İkinci eleştiri ölçekle ilgilidir: nesneler durum taşıdığı için, program çok sayıda değişebilir duruma bölünür. Nesneler birbirine referans tuttukça, bir değişikliğin nereye kadar yayıldığını izlemek güçleşir. Bu gözlem, sonraki dersin çıkış noktasıdır.
Özet
- Nesneye dayalı yaklaşım, veriyi ve onu işleyen davranışı tek bir birimde toplar.
- Sınıf bir tanım, nesne o tanımdan üretilmiş somut örnektir.
- Kapsülleme, veriye erişimi nesnenin işlemleriyle sınırlar; amacı değişmezleri tek bir yerde korumaktır.
- Arayüz ile gerçekleştirimin ayrılması, çağıranı etkilemeden iç yapının değiştirilmesine izin verir.
- Kalıtım ortak davranışı paylaştırır, çok biçimlilik türe göre davranışı koşul zinciri olmadan seçtirir.
- Yaklaşım, durumu olan varlıklarda güçlüdür; saf dönüşümlerde gereksiz katman üretir ve ölçekte yayılan değişebilir durum bir maliyettir.
Sonraki Adım
Değişebilir durumun izlenmesi güçleşiyorsa, akla gelen karşı fikir açıktır: durumu hiç değiştirmemek. Sonraki ders, hesaplamayı değer dönüşümü olarak ele alan fonksiyonel yaklaşımı tanıtacak ve aynı problemi üçüncü kez, bu kez hiçbir değeri değiştirmeden çözecek.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.