Bankacılık Sistemi
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 106 / 107.
Görev
KolayHesapları, 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) errorveWithdraw(amount float64) errormetotlarına sahip birTransactablearayüzü (interface) tanımlayın. Ardından bu arayüzü uygulayan iki hesap türü oluşturun:Dışa aktarılmayan (unexported)
id,holdervebalancealanlarına sahip birCheckingAccount. 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
minBalancealanına sahip birSavingsAccount. 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 (
NewCheckingAccountveNewSavingsAccount) ve birBalance() float64alı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 birTransactionyapısı (struct) oluşturun. Her işlemin birType(string: "deposit" veya "withdrawal"),Amount(float64) veAccountID(string) bilgisi vardır. BirNewTransactionyapılandırıcısı ve şu formatı döndüren birString() stringmetodu 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 birBankyapı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ırAddAccount(id string, account Transactable)— bir hesabı kaydederDeposit(accountID string, amount float64) error— bir hesaba para yatırır ve başarı durumunda işlemi kaydederWithdraw(accountID string, amount float64) error— bir hesaptan para çeker ve başarı durumunda işlemi kaydederTransfer(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ığındaErrInsufficientFunds— para çekme işlemi mevcut bakiyeyi aştığındaErrInvalidAmount— yatırma/çekme tutarı sıfır veya negatif olduğundaErrMinBalanceRequired— 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ü (
checkingveyasavings), 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çinError: [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.00Ve ş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 foundTransactable 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
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