Menu
Coddy logo textTech

Bankacılık Sistemi

Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 106 / 107.

challenge icon

Görev

Kolay

Hesapları, işlemleri ve finansal operasyonları yöneten bir Bankacılık Sistemi kuralım! Veri bütünlüğünün kritik olduğu sağlam bir sistem oluşturacaksınız; hesap bakiyeleri yalnızca doğrulanmış yöntemlerle değişmeli ve yetersiz bakiye veya geçersiz tutarlar gibi hatalar zarif bir şekilde ele alınmalıdır.

Kodunuzu beş dosya halinde düzenleyeceksiniz:

  • account.go: Deposit(amount float64) error ve Withdraw(amount float64) error metotlarına sahip bir Transactable arayüzü (interface) tanımlayın. Ardından bu arayüzü uygulayan iki hesap türü oluşturun:

    Dışa aktarılmayan (unexported) id, holder ve balance alanlarına sahip bir CheckingAccount. Vadesiz hesaplar (Checking accounts), bakiyeyi tam olarak sıfıra indiren ancak altına düşürmeyen para çekme işlemlerine izin verir.

    Aynı dışa aktarılmayan alanlara ek olarak bir minBalance alanına sahip bir SavingsAccount. Tasarruf hesapları (Savings accounts) minimum 100.0 bakiyeyi korumalıdır; bu eşiğin altına düşecek para çekme işlemleri başarısız olmalıdır.

    Her iki hesap türü de yapılandırıcılara (NewCheckingAccount ve NewSavingsAccount) ve bir Balance() float64 alıcı (getter) metoduna ihtiyaç duyar. Para yatırma işlemleri için negatif veya sıfır tutarları reddedin. Para çekme işlemleri için negatif veya sıfır tutarları ve mevcut fonları aşan tutarları reddedin.

  • transaction.go: Hesap hareketlerini kaydetmek için bir Transaction yapısı (struct) oluşturun. Her işlemin bir Type (string: "deposit" veya "withdrawal"), Amount (float64) ve AccountID (string) bilgisi vardır. Bir NewTransaction yapılandırıcısı ve şu formatı döndüren bir String() string metodu ekleyin: [Type] $[Amount] on [AccountID] (tutar iki ondalık basamakla formatlanmış olmalıdır).
  • bank.go: Birden fazla hesabı yöneten ve işlemleri kaydeden bir Bank yapısı oluşturun. Hesapları ID'ye göre bir map içinde saklayın ve işlemlerin bir dilimini (slice) tutun. Şunları uygulayın:
    • NewBank() *Bank — boş koleksiyonları başlatır
    • AddAccount(id string, account Transactable) — bir hesabı kaydeder
    • Deposit(accountID string, amount float64) error — bir hesaba para yatırır ve başarı durumunda işlemi kaydeder
    • Withdraw(accountID string, amount float64) error — bir hesaptan para çeker ve başarı durumunda işlemi kaydeder
    • Transfer(fromID, toID string, amount float64) error — hesaplar arasında parayı atomik olarak taşır (para çekme başarılı olur ancak yatırma başarısız olursa, çekme işlemini geri alın)
    • GetBalance(accountID string) (float64, error) — bir hesabın bakiyesini döndürür

    Var olmayan hesaplar için uygun hatalar döndürün.

  • errors.go: Bankacılık işlemleriniz için sentinel hatalar tanımlayın:
    • ErrAccountNotFound — bir hesap ID'si mevcut olmadığında
    • ErrInsufficientFunds — para çekme işlemi mevcut bakiyeyi aştığında
    • ErrInvalidAmount — yatırma/çekme tutarı sıfır veya negatif olduğunda
    • ErrMinBalanceRequired — tasarruf hesabı çekimi minimum bakiye kuralını ihlal ettiğinde
  • main.go: Bir banka oluşturun ve girdilere göre işlemleri gerçekleştirin.

    Oluşturulacak hesap sayısını okuyun. Her hesap için hesap türünü (checking veya savings), ID'yi, hesap sahibi adını ve başlangıç bakiyesini okuyun. Uygun hesap türünü oluşturun ve bankaya ekleyin.

    Ardından işlem sayısını okuyun. Her işlem şunlardan biridir:

    • deposit [accountID] [amount]
    • withdraw [accountID] [amount]
    • transfer [fromID] [toID] [amount]
    • balance [accountID]

    Her işlem için sonucu yazdırın: Başarılı yatırma/çekme/transfer işlemleri için OK, bakiye sorguları için iki ondalık basamakla formatlanmış bakiye veya sentinel hata mesajlarınızı kullanarak başarısızlıklar için Error: [message].

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

  • Hesap sayısı, ardından her hesabın türü, ID'si, sahibi, başlangıç bakiyesi (her biri 4 satır)
  • İşlem sayısı, ardından her işlem (her biri 1 satır)

Örneğin, şu girdi verildiğinde:

2
checking
ACC001
Alice
500.00
savings
ACC002
Bob
1000.00
6
deposit ACC001 200
balance ACC001
withdraw ACC002 950
withdraw ACC001 800
transfer ACC001 ACC002 100
balance ACC002

Çıktınız şu olmalıdır:

OK
700.00
Error: minimum balance required
Error: insufficient funds
OK
1000.00

Ve şu girdi verildiğinde:

1
checking
C100
Charlie
100.00
4
withdraw C100 100
balance C100
deposit C100 -50
withdraw C999 50

Çıktınız şu olmalıdır:

OK
0.00
Error: invalid amount
Error: account not found

Transactable arayüzünün Bankanın her iki hesap türüyle de tek tip çalışmasına nasıl izin verdiğine, her hesap türünün ise kendi kurallarını nasıl uyguladığına dikkat edin. Transfer metodu atomik operasyonları gösterir; bir şeyler yarı yolda ters giderse sistem tutarlı kalır!

Kendin dene

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)

	// Hesap sayısını oku
	scanner.Scan()
	numAccounts, _ := strconv.Atoi(scanner.Text())

	// Yeni bir banka oluştur
	bank := NewBank()

	// Hesapları oku ve oluştur
	for i := 0; i < numAccounts; i++ {
		scanner.Scan()
		accountType := scanner.Text()
		scanner.Scan()
		id := scanner.Text()
		scanner.Scan()
		holder := scanner.Text()
		scanner.Scan()
		balance, _ := strconv.ParseFloat(scanner.Text(), 64)

		// TODO: accountType değerine göre uygun hesap türünü oluşturun
		// ve onu bankaya ekleyin
		_ = accountType
		_ = id
		_ = holder
		_ = balance
	}

	// İşlem sayısını oku
	scanner.Scan()
	numOps, _ := strconv.Atoi(scanner.Text())

	// Her bir işlemi işle
	for i := 0; i < numOps; i++ {
		scanner.Scan()
		parts := strings.Fields(scanner.Text())
		operation := parts[0]

		// TODO: Her bir işlem türünü ele alın:
		// - "deposit": hesaba para yatır, "OK" veya hata yazdır
		// - "withdraw": hesaptan para çek, "OK" veya hata yazdır
		// - "transfer": hesaplar arası transfer yap, "OK" veya hata yazdır
		// - "balance": bakiyeyi al ve 2 ondalık basamak olacak şekilde formatlayarak yazdır
		_ = operation
	}
}

Nesne Yönelimli Programlama bölümündeki tüm dersler