Paket Seviyesinde Kapsülleme
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 48 / 107.
Önceki ders alan düzeyinde görünürlüğü kapsamış olsa da, Go'nun kapsülleme mekanizması aslında paket düzeyinde çalışır. Aynı paket içindeki her şey —hangi dosyada olduğuna bakılmaksızın— dışa aktarılmamış (unexported) alanlara ve fonksiyonlara erişebilir.
Birden fazla dosyaya sahip bir paketi düşünün:
// account/account.go
package account
type Account struct {
balance int // dışa aktarılmamış
}
func (a *Account) Deposit(amount int) {
a.balance += amount
}
// account/helper.go
package account
func ResetAccount(a *Account) {
a.balance = 0 // çalışır - aynı paket
}
Her iki dosya da account paketine aittir, bu nedenle helper.go dışa aktarılmamış balance alanına doğrudan erişebilir. Bu bilinçli bir tercihtir; dahili erişimi korurken paket mantığını dosyalar arasında bölmenize olanak tanır.
Ancak, paket dışındaki kodlar dışa aktarılmamış (unexported) üyelere erişemez:
// main.go
package main
import "account"
func main() {
acc := &account.Account{}
acc.Deposit(100) // çalışır - dışa aktarılmış metot
// acc.balance = 50 // hata - dışa aktarılmamış alan
// account.ResetAccount // ResetAccount dışa aktarılmış olsaydı çalışırdı
}
Bu paket düzeyindeki sınır, Go'nun birincil kapsülleme mekanizmasıdır. Paketleri, dahili kodun serbestçe iş birliği yaptığı, harici kodun ise yalnızca dışa aktarılan API aracılığıyla etkileşime girdiği uyumlu birimler olarak tasarlarsınız. Her paketi, net bir genel arayüze sahip, kendi kendine yeten bir modül olarak düşünün.
Görev
KolayAynı paket içindeki birden fazla dosyanın, dış kodlardan verileri gizli tutarken, dışa aktarılmamış (unexported) alanlara doğrudan erişerek nasıl birlikte çalışabileceğini gösteren bir envanter yönetim sistemi kuralım.
main paketi içinde birlikte çalışan üç dosya oluşturacaksınız:
product.go: Dışa aktarılmış birNamealanına ve dışa aktarılmamış birquantityalanına (int) sahip birProductyapısı (struct) tanımlayın. Şu formatı döndüren dışa aktarılmış birInfo() stringmetodu ekleyin:[Name]: [quantity] in stockinventory.go: Dışa aktarılmamışquantityalanına doğrudan erişerek (aynı pakette oldukları için mümkündür) ürünlerle çalışan yardımcı fonksiyonlar oluşturun. Şunları uygulayın:Restock(p *Product, amount int)- miktarı ürünün adedine eklerSell(p *Product, amount int) bool- yeterli stok varsa miktarı adetten çıkarır, başarılıysatrue, yeterli stok yoksafalsedöndürürNewProduct(name string, initialQty int) *Product- verilen isim ve başlangıç miktarıyla bir ürün oluşturan yapıcı (constructor) fonksiyon
main.go: Girdiden ürün detaylarını okuyun, yapıcıyı kullanarak bir ürün oluşturun, envanter işlemlerini gerçekleştirin ve sonuçları görüntüleyin. Her işlemden sonra, güncellenmiş durumu göstermek için ürün bilgisini yazdırın.
Aşağıdaki girdiler sağlanacaktır:
- Satır 1: Ürün adı
- Satır 2: Başlangıç miktarı (tam sayı)
- Satır 3: Stok ekleme miktarı (tam sayı)
- Satır 4: Satış miktarı (tam sayı)
Ürünü oluşturduktan sonra başlangıç bilgisini yazdırın. Ardından stok ekleyin ve bilgiyi tekrar yazdırın. Son olarak, satış yapmayı deneyin ve ya güncellenmiş bilgiyi (başarılıysa) ya da Sale failed: insufficient stock (yeterli miktar yoksa) yazdırın.
Örneğin, Laptop, 10, 5 ve 8 verildiğinde çıktınız şöyle olmalıdır:
Laptop: 10 in stock
Laptop: 15 in stock
Laptop: 7 in stockVe Phone, 3, 2 ve 10 verildiğinde çıktınız şöyle olmalıdır:
Phone: 3 in stock
Phone: 5 in stock
Sale failed: insufficient stockBuradaki temel nokta, inventory.go dosyasının product.go ile aynı pakette olduğu için dışa aktarılmamış quantity alanını doğrudan okuyabilmesi ve değiştirebilmesidir. Bu, paket düzeyinde kapsüllemenin (encapsulation) bir örneğidir; veriler dış paketlerden korunurken paket içi iş birliği serbestçe gerçekleşir.
Kopya kağıdı
Go'un kapsülleme (encapsulation) mekanizması dosya düzeyinde değil, paket düzeyinde çalışır. Aynı paket içindeki tüm dosyalar, hangi dosyada tanımlandıklarına bakılmaksızın dışa aktarılmamış (unexported) alanlara ve fonksiyonlara erişebilir.
Paket Düzeyinde Erişim
Dışa aktarılmamış üyeler, aynı paketteki tüm dosyalar arasında erişilebilirdir:
// account/account.go
package account
type Account struct {
balance int // dışa aktarılmamış
}
func (a *Account) Deposit(amount int) {
a.balance += amount
}
// account/helper.go
package account
func ResetAccount(a *Account) {
a.balance = 0 // çalışır - aynı paket
}
Harici Paket Kısıtlamaları
Paket dışındaki kodlar, dışa aktarılmamış üyelere erişemez:
// main.go
package main
import "account"
func main() {
acc := &account.Account{}
acc.Deposit(100) // çalışır - dışa aktarılmış metot
// acc.balance = 50 // hata - dışa aktarılmamış alan
}
Bu tasarım, dahili erişimi korurken paket mantığını birden fazla dosyaya bölmenize olanak tanıyarak net genel (public) arayüzlere sahip uyumlu birimler oluşturmanızı sağlar.
Kendin dene
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Ürün adını oku
name, _ := reader.ReadString('\n')
name = strings.TrimSpace(name)
// Başlangıç miktarını oku
initialQtyStr, _ := reader.ReadString('\n')
initialQty, _ := strconv.Atoi(strings.TrimSpace(initialQtyStr))
// Stok yenileme miktarını oku
restockStr, _ := reader.ReadString('\n')
restockAmount, _ := strconv.Atoi(strings.TrimSpace(restockStr))
// Satış miktarını oku
sellStr, _ := reader.ReadString('\n')
sellAmount, _ := strconv.Atoi(strings.TrimSpace(sellStr))
// TODO: NewProduct yapısını kullanarak yeni bir ürün oluşturun
// TODO: Başlangıç ürün bilgilerini yazdırın
// TODO: Ürün stoğunu yenileyin ve bilgileri yazdırın
// TODO: Satış yapmayı deneyin ve sonucu yazdırın
// Satış başarılı olursa, güncellenmiş bilgileri yazdırın
// Satış başarısız olursa, "Sale failed: insufficient stock" yazdırın
fmt.Println() // Gerçek çıktı ile değiştirin
}
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 Pool