Go'da Bilgi Gizleme
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 50 / 107.
Bilgi gizleme, yalnızca alanları dışa aktarılmamış hâle getirmenin ötesine geçer. Mesele, türlerinizi dış kodun yalnızca bilmesi gerekenleri bilecek şekilde tasarlamaktır. Daha fazlasını değil.
Amaç, iç yapıyı tamamen gizli tutarken metotlar aracılığıyla davranışı ortaya koymaktır. Şu yaklaşımı göz önünde bulundurun:
type Counter struct {
value int
maxLimit int
}
func NewCounter(limit int) *Counter {
return &Counter{maxLimit: limit}
}
func (c *Counter) Increment() bool {
if c.value >= c.maxLimit {
return false
}
c.value++
return true
}
func (c *Counter) Value() int {
return c.value
}
Harici kod, Counter öğesinin dahili olarak bir int kullandığını bilmez. Bu, bir float64, bir dilim veya tamamen başka bir şey olabilir. Yöntemler aynı şekilde davrandığı sürece, Counter kullanan hiçbir kod etkilenmeden uygulama değiştirilebilir.
Bu ilke yardımcı işlevler için de geçerlidir. İç mantığı dışa aktarmayın:
// Exported - public API'nin parçası
func (c *Counter) Reset() {
c.value = 0
}
// unexported - dahili yardımcı
func (c *Counter) isAtLimit() bool {
return c.value >= c.maxLimit
}
isAtLimit() öğesini gizleyerek, daha sonra onu değiştirmekte veya kaldırmakta özgürsünüz. Bilgi gizleme, paketinizin harici kullanıcılara ne vaat ettiği ile dahili olarak nasıl çalıştığı arasında net bir sınır oluşturur.
Görev
KolayBilgi gizlemeyi gösteren güvenli bir cüzdan sistemi oluşturalım. Dahili bakiye takibinin ve işlem geçmişinin harici koddan tamamen gizlendiği bir dijital cüzdan oluşturacaksın: yalnızca davranış metotlar aracılığıyla açığa çıkarılacak.
Kodunu iki dosyaya ayıracaksın:
wallet.go: Tüm dahili durumunu gizleyen birWalletyapısı oluştur. Cüzdan, mevcut bakiyeyi ve harcama limitini dahili olarak takip etmeli; ancak harici kod bunların nasıl saklandığını veya temsil edildiğini asla bilmemeli. Davranışı şu metotlar aracılığıyla açığa çıkar:NewWallet(limit float64) *Wallet- verilen harcama limitiyle ve sıfır bakiyeyle bir cüzdan oluşturan oluşturucuDeposit(amount float64) bool- cüzdana para ekler, başarılıysatruedöndürür (miktar pozitif olmalıdır)Spend(amount float64) bool- yeterli bakiye varsa VE miktar harcama limitini aşmıyorsa parayı çıkarır, başarılıysatruedöndürürBalance() float64- mevcut bakiyeyi döndürürStatus() string- şu biçimde bir durum mesajı döndürür:Balance: $[balance] (Limit: $[limit])
main.go: Cüzdan yapılandırmasını ve işlemleri girdiden oku, bir cüzdan oluştur, işlemleri gerçekleştir ve her eylemden sonra sonuçları görüntüle.
Aşağıdaki girdiler sağlanacaktır:
- 1. satır: Harcama limiti
- 2. satır: Para yatırma miktarı
- 3. satır: İlk harcama miktarı
- 4. satır: İkinci harcama miktarı
Cüzdanı oluşturduktan sonra başlangıç durumunu yazdır. Ardından her işlemi gerçekleştir ve başarılıysa güncellenmiş durumu, işlem reddedildiyse Transaction failed yazdır. Tüm dolar miktarlarını iki ondalık basamakla biçimlendir.
Örneğin 50, 100, 30 ve 80 verildiğinde çıktın şu şekilde olmalıdır:
Balance: $0.00 (Limit: $50.00)
Balance: $100.00 (Limit: $50.00)
Balance: $70.00 (Limit: $50.00)
Transaction failedSon işlem başarısız olur çünkü $80, yeterli bakiye olmasına rağmen $50 harcama limitini aşar. Cüzdan, bu kararları nasıl verdiğini açığa çıkarmadan kurallarını dahili olarak uygular. Harici kod yalnızca metotları çağırır ve sonuçları alır; dahili uygulama ayrıntılarını asla bilmez.
Kendin dene
package main
import (
"fmt"
)
func main() {
// Girdileri oku
var limit float64
var depositAmount float64
var spend1 float64
var spend2 float64
fmt.Scanln(&limit)
fmt.Scanln(&depositAmount)
fmt.Scanln(&spend1)
fmt.Scanln(&spend2)
// TODO: Verilen harcama limiti ile yeni bir cüzdan oluştur
// TODO: İlk durumu yazdır
// TODO: Perform deposit and print result (status or "Transaction failed")
// TODO: İlk harcamayı gerçekleştir ve sonucu yazdır
// TODO: İkinci harcamayı gerçekleştir ve sonucu yazdır
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1Go OOP Temelleri
Harici DosyalarGo Çalışma Alanı ve ModüllerPaketler ve İçe AktarmalarDışa Aktarılan ve Aktarılmayan İsimlerGo'da OOP'ye GirişSınıf Olarak Struct'larStruct'larda Metot TanımlamaPointer ve Değer AlıcılarStruct BaşlatmaYapıcı FonksiyonlarÖzet - Basit Hesap Makinesi4Arayüzler
Arayüzlere GirişÖrtük UygulamaSözleşme Olarak ArayüzBoş Arayüz (any)Tür OnaylamaTür SeçimiArayüz BileşimiStringer ve Error ArayüzleriÖzet - Şekil Hesaplayıcı7Kapsülleme
Dışa Aktarılan ve Aktarılmayan AlanlarPaket Seviyesinde KapsüllemeGetter ve Setter MetotlarıGo'da Bilgi GizlemeÖzet - Öğrenci Kayıtları10Generics (Go 1.18+)
Generics'e GirişTür ParametreleriTür KısıtlamalarıGeneric Struct'larGeneric Metotlar İçin Geçici ÇözümÖzet - Generic Koleksiyon13Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıAbstract Factory KalıbıObserver KalıbıStrategy Kalıbı2Türler ve Struct'lar: Derinlemesine İnceleme
Temel ve Bileşik TürlerÖzel Tür TanımlamalarıStruct EtiketleriAnonim Struct'larİç İçe Geçmiş Struct'larSıfır Değerler ve VarsayılanlarÖzet - Rehber5Kalıtım Yerine Kompozisyon
Go'da Neden Kalıtım YokStruct Gömme TemelleriMetot YükseltmeBirden Fazla Struct GömmeGömme vs AgregasyonGömülü Metotları GölgelemeÖzet - Çalışan Hiyerarşisi8Hata Yönetimi ve OOP
error ArayüzüÖzel Hata TürleriHata Sarmalama (fmt.Errorf)Sentinel Hatalarerrors.Is() ve errors.As()Panic, Defer ve RecoverÖzet - Dosya Ayrıştırıcı3İşaretçiler ve Bellek
Go'da İşaretçi TemelleriStruct İşaretçileriDeğer ile Geçme ve Referans ile Geçmenew() FonksiyonuGo'da Garbage CollectionÖzet - Linked List Oluşturucu6Go'da Polimorfizm
Interface'ler ile PolimorfizmGo'da Duck TypingInterface Karşılama KurallarıPolimorfik KoleksiyonlarDependency InjectionÖzet - Payment Processor9Eşzamanlılık ve OOP
Goroutine TemelleriKanallar ve İletişimTamponlu ve Tamponsuz KanallarSelect İfadesisync.Mutex ve sync.RWMutexsync.WaitGroupThread-Safe Struct TasarımıÖzet - Worker PoolKendi başına pratik yap: Online Go derleyicisi