Menu
Coddy logo textTech

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

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

challenge icon

Задание

Легко

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

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

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

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

    SavingsAccount с теми же неэкспортируемыми полями плюс поле minBalance. Сберегательные счета должны поддерживать минимальный баланс 100.0 — операции по снятию средств, которые приведут к падению ниже этого порога, должны завершаться ошибкой.

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

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

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

  • errors.go: Определите именованные ошибки (sentinel errors) для ваших банковских операций:
    • ErrAccountNotFound — когда ID счета не существует
    • ErrInsufficientFunds — когда сумма снятия превышает доступный баланс
    • ErrInvalidAmount — когда сумма депозита/снятия равна нулю или отрицательна
    • ErrMinBalanceRequired — когда снятие со сберегательного счета нарушит требование минимального баланса
  • main.go: Создайте банк и обрабатывайте операции на основе входных данных.

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

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

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

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

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

  • Количество счетов, затем тип каждого счета, ID, владелец, начальный баланс (по 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 позволяет банку единообразно работать с обоими типами счетов, в то время как каждый тип счета применяет свои собственные правила. Метод 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Финальные испытания

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