Menu
Coddy logo textTech

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, alanları sadece dışa aktarılmamış (unexported) yapmanın ötesine geçer. Bu, türlerinizi harici kodun sadece bilmesi gerekeni bileceği —daha fazlasını değil— şekilde tasarlamakla ilgilidir.

Amaç, iç yapıyı tamamen gizli tutarken metotlar aracılığıyla davranışı ortaya çıkarmaktır. Şu yaklaşımı düşünün:

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
}

Dış kod, Counter'ın dahili olarak bir int kullandığını bilmez. Bir float64, bir slice veya tamamen başka bir şey olabilir. Metotlar aynı şekilde davrandığı sürece, uygulama Counter'ı kullanan hiçbir kodu etkilemeden değişebilir.

Bu ilke yardımcı fonksiyonlar için de geçerlidir. Dahili mantığı dışa aktarılmamış (unexported) olarak tutun:

// Dışa aktarıldı - genel API'nin bir parçası
func (c *Counter) Reset() {
    c.value = 0
}

// dışa aktarılmadı - dahili yardımcı
func (c *Counter) isAtLimit() bool {
    return c.value >= c.maxLimit
}

isAtLimit() fonksiyonunu gizleyerek, onu daha sonra değiştirmekte veya kaldırmakta özgür kalırsınız. Bilgi gizleme, paketinizin dış kullanıcılara vaat ettikleri ile dahili olarak nasıl çalıştığı arasında net bir sınır oluşturur.

challenge icon

Görev

Kolay

Bilgi gizlemeyi (information hiding) 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, yalnızca davranışların metotlar aracılığıyla dışarıya açıldığı dijital bir cüzdan oluşturacaksınız.

Kodunuzu iki dosya halinde düzenleyeceksiniz:

  • wallet.go: Tüm dahili durumunu gizleyen bir Wallet yapısı (struct) oluşturun. Cüzdan, mevcut bakiyeyi ve harcama limitini dahili olarak takip etmelidir, ancak harici kod bunların nasıl saklandığını veya temsil edildiğini asla bilmemelidir. Davranışları şu metotlar aracılığıyla dışarıya açın:
    • NewWallet(limit float64) *Wallet - verilen harcama limiti ve sıfır bakiye ile bir cüzdan oluşturan yapıcı (constructor) fonksiyon
    • Deposit(amount float64) bool - cüzdana para ekler, başarılıysa (miktar pozitif olmalıdır) true döner
    • Spend(amount float64) bool - yeterli bakiye varsa VE miktar harcama limitini aşmıyorsa parayı çeker, başarılıysa true döner
    • Balance() float64 - mevcut bakiyeyi döner
    • Status() string - şu formatta bir durum mesajı döner: Balance: $[balance] (Limit: $[limit])
    Herhangi bir yardımcı mantığı (bir işlemin geçerli olup olmadığını kontrol etmek gibi) dışa aktarılmamış (unexported) fonksiyonlar veya metotlar olarak tutun; bunlar daha sonra değişebilecek dahili uygulama detaylarıdır.
  • main.go: Girdiden cüzdan yapılandırmasını ve işlemleri okuyun, bir cüzdan oluşturun, işlemleri gerçekleştirin ve her eylemden sonra sonuçları görüntüleyin.

Aşağıdaki girdiler sağlanacaktır:

  • Satır 1: Harcama limiti
  • Satır 2: Yatırılacak miktar
  • Satır 3: İlk harcama miktarı
  • Satır 4: İkinci harcama miktarı

Cüzdanı oluşturduktan sonra başlangıç durumunu yazdırın. Ardından her işlemi gerçekleştirin ve güncellenmiş durumu (başarılıysa) veya Transaction failed (işlem reddedildiyse) mesajını yazdırın. Tüm dolar miktarlarını iki ondalık basamakla formatlayın.

Örneğin, 50, 100, 30 ve 80 verildiğinde çıktınız şöyle olmalıdır:

Balance: $0.00 (Limit: $50.00)
Balance: $100.00 (Limit: $50.00)
Balance: $70.00 (Limit: $50.00)
Transaction failed

Son işlem başarısız olur çünkü yeterli bakiye olmasına rağmen $80, $50 olan harcama limitini aşmaktadır. Cüzdan, bu kararları nasıl verdiğini ifşa etmeden kurallarını dahili olarak uygular. Harici kod sadece metotları çağırır ve sonuçları alır, dahili uygulama detaylarını asla bilmez.

Kopya kağıdı

Bilgi gizleme (information hiding), türleri harici kodun yalnızca bilmesi gerekenleri bileceği şekilde tasarlamak anlamına gelir. İç yapıyı tamamen gizli tutarken, metotlar aracılığıyla davranışı dışarı açın.

Gizli uygulamaya (implementation) sahip bir tür örneği:

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 iç temsili bilmez (bu int, float64 veya başka bir şey olabilir). Uygulama, onu kullanan kodu etkilemeden değişebilir.

Yardımcı fonksiyonları dışa aktarılmamış (unexported) tutun:

// Dışa aktarılmış - genel API'nin parçası
func (c *Counter) Reset() {
    c.value = 0
}

// dışa aktarılmamış - dahili yardımcı
func (c *Counter) isAtLimit() bool {
    return c.value >= c.maxLimit
}

Bilgi gizleme, paketinizin dışarıya vaat ettikleri ile dahili olarak nasıl çalıştığı arasında net bir sınır oluşturur.

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şturun

	// TODO: Başlangıç durumunu yazdırın

	// TODO: Para yatırma işlemini gerçekleştirin ve sonucu yazdırın (durum veya "Transaction failed")

	// TODO: İlk harcamayı gerçekleştirin ve sonucu yazdırın

	// TODO: İkinci harcamayı gerçekleştirin ve sonucu yazdırın
}
quiz iconKendini test et

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