Menu
Coddy logo textTech

Банковская система

Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy. Урок 106 из 107.

challenge icon

Задание

Легко

Давайте создадим Banking System, которая управляет account, транзакциями и финансовыми операциями! Вы создадите надёжную систему, где целостность данных критически важна: балансы account должны изменяться только через проверенные методы, а такие ошибки, как овердрафт или недопустимые суммы, должны обрабатываться корректно.

Вы распределите код по пяти файлам:

  • account.go: Define интерфейс Transactable с методами Deposit(amount float64) error и Withdraw(amount float64) error. Затем создайте два типа account, реализующих этот интерфейс:

    CheckingAccount с неэкспортируемыми полями id, holder и balance. Checking account позволяют выполнять снятие средств, при котором баланс становится ровно нулевым, но не опускается ниже нуля.

    SavingsAccount с теми же неэкспортируемыми полями и дополнительным полем minBalance. Savings account должны поддерживать минимальный баланс 100.0: снятие средств, в результате которого баланс станет ниже этого порога, должно завершаться ошибкой.

    Оба типа account должны иметь конструкторы (NewCheckingAccount и NewSavingsAccount) и метод-геттер Balance() float64. Для пополнений отклоняйте отрицательные и нулевые суммы. Для снятий отклоняйте отрицательные и нулевые суммы, а также суммы, превышающие available средства.

  • transaction.go: Create структуру Transaction для записи activity account. Каждая транзакция содержит Type (string: "deposit" или "withdrawal"), Amount (float64) и AccountID (string). Добавьте конструктор NewTransaction и метод String() string, возвращающий формат: [Type] $[Amount] on [AccountID], где сумма отформатирована с двумя знаками после десятичной точки.
  • bank.go: Создайте структуру Bank, которая управляет несколькими account и записывает транзакции. Храните account в map по ID и используйте срез транзакций. Реализуйте:
    • NewBank() *Bank: инициализирует empty коллекции
    • AddAccount(id string, account Transactable): регистрирует account
    • Deposit(accountID string, amount float64) error: пополняет account и записывает транзакцию при успешном выполнении
    • Withdraw(accountID string, amount float64) error: снимает средства с account и записывает транзакцию при успешном выполнении
    • Transfer(fromID, toID string, amount float64) error: atomically перемещает средства между account (если снятие прошло успешно, но пополнение завершилось ошибкой, отмените снятие)
    • GetBalance(accountID string) (float64, error): возвращает баланс account

    Возвращайте appropriate ошибки для несуществующих account.

  • errors.go: Define sentinel-ошибки для банковских операций:
    • ErrAccountNotFound: когда ID account doesn существует
    • ErrInsufficientFunds: когда снятие превышает available баланс
    • ErrInvalidAmount: когда сумма пополнения или снятия равна нулю либо отрицательна
    • ErrMinBalanceRequired: когда снятие из savings account нарушает минимальный баланс
  • main.go: Создайте bank и обработайте операции на основе входных данных.

    Прочитайте количество account, которые необходимо создать. Для каждого account прочитайте тип account (checking или savings), ID, имя holder и начальный баланс. Создайте appropriate тип account и добавьте его в bank.

    Затем прочитайте количество операций. Каждая операция представляет собой одну из следующих:

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

    Для каждой операции выведите результат: OK для успешных пополнений, снятий и переводов, баланс с двумя знаками после десятичной точки для запросов баланса или Error: [message] в случае ошибки, используя сообщения sentinel-ошибок.

Будут предоставлены следующие входные данные:

  • Количество account, затем тип, ID, holder и начальный баланс каждого account (по 4 строки на каждый)
  • Количество операций, затем каждая операция (по 1 строке на каждую)

Например, для следующих данных:

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

Вывод должен быть таким:

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

А для следующих данных:

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

Вывод должен быть таким:

OK
0.00
Error: invalid amount
Error: account not found

Обратите внимание, как интерфейс Transactable позволяет Bank единообразно работать с обоими типами account, в то время как каждый тип account применяет собственные правила. Метод Transfer демонстрирует атомарные операции: если на каком-либо этапе что-то пойдёт не так, система сохранит согласованность!

Попробуйте сами

package main

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

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

	// Прочитать количество счетов
	scanner.Scan()
	numAccounts, _ := strconv.Atoi(scanner.Text())

	// Создать новый банк
	bank := NewBank()

	// Прочитать и создать счета
	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
		// и добавить его в банк
		_ = accountType
		_ = id
		_ = holder
		_ = balance
	}

	// Прочитать количество операций
	scanner.Scan()
	numOps, _ := strconv.Atoi(scanner.Text())

	// Обработать каждую операцию
	for i := 0; i < numOps; i++ {
		scanner.Scan()
		parts := strings.Fields(scanner.Text())
		operation := parts[0]

		// TODO: Обработать каждый тип операции:
		// - "deposit": внести на счёт, вывести "OK" или ошибку
		// - "withdraw": снять со счёта, вывести "OK" или ошибку
		// - "transfer": перевести между счетами, вывести "OK" или ошибку
		// - "balance": получить и вывести баланс, отформатированный до 2 знаков после запятой
		_ = operation
	}
}

Все уроки раздела Объектно-ориентированное программирование

16Финальные испытания

Платформа онлайн-обученияБанковская системаСистема игровых персонажей

Потренируйтесь самостоятельно: Онлайн-компилятор Go