Kapsülleme, property ve geçerli durum
Bir sınıf yazmak, nitelikleri dış dünyaya açıp birkaç metot eklemekten ibaret değildir. Nesnenin her zaman anlamlı bir durumda kalması gerekir. Bu hafta kapsülleme (encapsulation) fikrini, kontrollü durum değişimini ve değişmez koşul (invariant) kavramını kullanacağız.
Bu hafta neleri yapabilmelisiniz?
- kapsüllemenin amacını “veriyi gizlemek”ten daha geniş biçimde açıklayabilmeli,
- bir nesnenin invariant’ını belirleyebilmeli,
- başlangıç durumunu
__init__içinde doğrulayabilmeli, - durum değişimlerini metotlarla sınırlandırabilmeli,
propertyile kontrollü okuma/yazma arayüzü kurabilmeli,- geçersiz girişte nesneyi yarım değiştirilmiş durumda bırakmamalısınız.
Değişmez koşul (invariant) nedir?
Değişmez koşul (invariant), nesnenin geçerli kabul edildiği her anda doğru olması gereken kuraldır.
Bir banka hesabı için örnek kural:
balance >= 0
Bir ürün için:
price > 0vestock >= 0
Bir ders kaydı için:
0 <= score <= 100
Bu kurallar yalnızca veri doğrulama ayrıntısı değil, nesnenin ne anlama geldiğinin bir parçasıdır.
Geçersiz başlangıcı engellemek
Nesne ilk andan itibaren geçerli olmalıdır.
Kontrollü durum değişimi
_balance başındaki tek alt çizgi “bu niteliği sınıfın iç detayı olarak kabul et” biçiminde bir programcı sözleşmesidir. Python bunu teknik olarak tamamen erişilemez yapmaz.

deposit ile withdraw metotları üzerinden yapılması.Amaç, nesnenin durumunun hangi kurallarla değişeceğini tek bir güvenilir arayüzde toplamaktır. Python’da kapsülleme çoğu zaman katı erişim engelinden çok sorumluluk ve arayüz disiplini ile sağlanır.
property ne zaman anlamlı?
Bir niteliği kullanıcıya account.balance biçiminde okunabilir sunmak ama değişimini kontrol altında tutmak isteyebiliriz.
@property
def balance(self):
return self._balanceBu durumda account.balance okunabilir; ancak setter tanımlamadığımız için normal account.balance = -100 ataması yapılamaz.
Bazı durumlarda setter anlamlıdır:
Setter, doğrudan atama sözdizimini korurken kuralı tek noktada uygular.
Fail fast
Geçersiz durum ortaya çıktığında sorunu mümkün olduğunca erken bildirmek genellikle daha güvenlidir:
Product("Klavye", -100)oluşturulurken hata vermesi, negatif fiyatın sistemde dolaşıp çok daha sonra yanlış rapor üretmesinden iyidir.
Yarım güncelleme tehlikesi
Şu metodu düşünün:
def transfer_to(self, other, amount):
self._balance -= amount
if self._balance < 0:
raise ValueError("Yetersiz bakiye")
other._balance += amountKontrol değişiklikten sonra yapılmıştır. Hata üretildiğinde self._balance zaten negatif olmuş olabilir.
Daha güvenli sıra:
- tüm ön koşulları kontrol et,
- sonra durumu değiştir.
Bu ilkeyi dönem boyunca kullanacağız.
Alıştırma — Invariant belirle
Aşağıdaki sınıflar için en az iki invariant yazın:
StudentProductReservation
Örneğin tarihlerin sırası, puan aralığı, pozitif fiyat, negatif olmayan stok gibi kurallar düşünün.
Alıştırma — Güvenli withdraw
if amount <= 0:
raise ValueError("Tutar pozitif olmalı")
if amount > self._balance:
raise ValueError("Yetersiz bakiye")Alıştırma — Property mi metot mu?
Aşağıdakileri tartışın:
account.balanceaccount.withdraw(100)rectangle.areaorder.cancel()
Hangileri “durumdan hesaplanan bir özellik” gibi, hangileri “eylem/komut” gibi okunuyor? Python’da her şeyi property yapmak da her şeyi get_...() metoduna dönüştürmek de gerekli değildir. Arayüzün niyetini açık kılın.
Küçük üretim görevi — Güvenli ürün
Product sınıfı yazın:
name: boş olamaz,price: 0’dan büyük olmalı,stock: negatif olamaz.
Metotlar:
add_stock(amount)sell(amount)
sell yetersiz stokta hata vermeli ve stok değerini değiştirmemelidir. Fiyatı property üzerinden okunabilir yapın; setter ekleyip eklememeye tasarım gerekçesiyle karar verin.
Kendinizi kontrol edin
- Invariant nedir?
- Neden doğrulama yalnızca kullanıcı arayüzünde yapılmamalıdır?
_balancePython’da gerçekten erişilemez midir?propertyhangi durumda kullanışlıdır?- Neden önce doğrulayıp sonra durumu değiştirmek daha güvenlidir?
Bu haftadan akılda kalması gerekenler
- Kapsülleme, nesnenin geçerli durumunu koruyan bir sorumluluk sınırıdır.
- Invariant, nesnenin her geçerli durumda sağlaması gereken kuraldır.
- Başlangıç ve durum geçişleri doğrulanmalıdır.
_namebir erişim yasağı değil, iç kullanım niyetidir.property, arayüzü sade tutarken kontrol ekleyebilir.