Банковская система
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 104 из 104.
Задание
ЛегкоДавайте создадим банковскую систему, демонстрирующую паттерн State, наследование и управление интеллектуальными указателями. Вы создадите систему, в которой счета могут находиться в разных состояниях (Active, Frozen, Closed), каждое из которых имеет собственное поведение при обработке транзакций.
Вы распределите код по шести файлам:
AccountState.h: определите инфраструктуру паттерна State для состояний счетов.Создайте абстрактный базовый класс
AccountStateс чистыми виртуальными методами:deposit(double amount): возвращает true, если внесение средств разрешено, и false в противном случаеwithdraw(double amount): возвращает true, если снятие средств разрешено, и false в противном случаеgetStateName(): возвращает название состояния в виде строки
Реализуйте три конкретных состояния:
ActiveState: разрешает как внесение, так и снятие средств, возвращает"Active"FrozenState: разрешает внесение средств, но отклоняет снятие, возвращает"Frozen"ClosedState: отклоняет как внесение, так и снятие средств, возвращает"Closed"
Account.h: создайте иерархию счетов с управлением состояниями.Создайте базовый класс
Accountсо следующими элементами:- Номер счета (строка), имя владельца и баланс
std::unique_ptr<AccountState>для управления текущим состояниемdeposit(double amount): сначала проверяет состояние; если операция разрешена, добавляет сумму к балансу и выводит"Deposited [amount] to [accountNumber]", в противном случае выводит"Deposit rejected: account is [stateName]"withdraw(double amount): проверяет состояние; если операция разрешена и средств достаточно, вычитает сумму и выводит"Withdrew [amount] from [accountNumber]". Если состояние отклоняет операцию, выведите"Withdrawal rejected: account is [stateName]". Если средств недостаточно, выведите"Insufficient funds"freeze(),activate()иclose(): изменяют состояние счетаgetInfo(): возвращает"[accountNumber] ([ownerName]): $[balance] - [stateName]"- Виртуальный
getAccountType(), возвращающий"Basic"
Создайте два производных типа счетов:
SavingsAccount: имеет требование минимального баланса (передается конструктору). Переопределите withdraw, чтобы также проверять, не опустится ли баланс ниже минимального; если опустится, выведите"Cannot go below minimum balance of [minimum]". Для типа счета возвращает"Savings".CheckingAccount: имеет лимит овердрафта (передается конструктору). Разрешает снятие средств в пределах значения (баланс + overdraftLimit). Для типа счета возвращает"Checking".
Transaction.h: представьте транзакции в виде объектов.Создайте класс
Transaction, который записывает:- Тип транзакции (строка: "Deposit", "Withdrawal", "Transfer")
- Сумму
- Номер задействованного счета
- Статус успешности (bool)
Добавьте метод
getDescription(), возвращающий"[type]: $[amount] on [accountNumber] - [Success/Failed]"Customer.h: создайте клиента, которому принадлежат несколько счетов.У
Customerесть имя, идентификатор и вектор изstd::shared_ptr<Account>. Реализуйте:addAccount(std::shared_ptr<Account> account)getAccount(const std::string& accountNumber): возвращает соответствующий счет или nullptrgetTotalBalance(): суммирует балансы всех счетовlistAccounts(): выводит информацию о каждом счете
Bank.h: координируйте банковские операции.Класс
Bankхранит клиентов и ведет историю транзакций. Реализуйте:addCustomer(std::shared_ptr<Customer> customer)findAccount(const std::string& accountNumber): ищет счет среди всех клиентовprocessDeposit(const std::string& accountNumber, double amount): находит счет, выполняет внесение средств и записывает транзакциюprocessWithdrawal(const std::string& accountNumber, double amount): находит счет, выполняет снятие средств и записывает транзакциюgetTransactionCount(): возвращает общее количество обработанных транзакций
main.cpp: продемонстрируйте работу банковской системы.Прочитайте четыре входных значения:
- Данные клиента (формат:
name,customerId) - Данные сберегательного счета (формат:
accountNumber,minBalance) - Операция 1 (формат:
action,accountNumber,amount, где action — этоdepositилиwithdraw) - Операция 2 (формат:
action,accountNumber,amountилиfreeze,accountNumber)
Создайте банк и клиента. Создайте сберегательный счет, указав клиента в качестве владельца, и добавьте его клиенту. Добавьте клиента в банк. Обработайте обе операции (если это команда freeze, заморозьте счет, а затем выполните небольшое снятие в размере $10, чтобы продемонстрировать работу состояния). Наконец, выведите список счетов клиента и общее количество транзакций в формате
"Transactions: [count]".- Данные клиента (формат:
Например, для входных данных Alice,C001, SAV001,100, deposit,SAV001,500 и withdraw,SAV001,200:
Deposited 500 to SAV001
Withdrew 200 from SAV001
SAV001 (Alice): $300 - Active
Transactions: 2Для входных данных Bob,C002, SAV002,50, deposit,SAV002,100 и freeze,SAV002:
Deposited 100 to SAV002
Withdrawal rejected: account is Frozen
SAV002 (Bob): $100 - Frozen
Transactions: 2Для входных данных Carol,C003, SAV003,200, deposit,SAV003,250 и withdraw,SAV003,100:
Deposited 250 to SAV003
Cannot go below minimum balance of 200
SAV003 (Carol): $250 - Active
Transactions: 2В этом задании объединяются паттерн State для управления поведением счетов, наследование для разных типов счетов, интеллектуальные указатели для отношений владения и отслеживание транзакций — все основные концепции, которые вы освоили на протяжении курса.
Попробуйте сами
#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include "Bank.h"
int main() {
// Прочитать ввод 1: данные клиента (формат: name,customerId)
std::string customerInput;
std::getline(std::cin, customerInput);
// Прочитать ввод 2: данные сберегательного счёта (формат: accountNumber,minBalance)
std::string accountInput;
std::getline(std::cin, accountInput);
// Прочитать ввод 3: операция 1 (формат: action,accountNumber,amount)
std::string op1Input;
std::getline(std::cin, op1Input);
// Прочитать ввод 4: операция 2 (формат: action,accountNumber,amount или freeze,accountNumber)
std::string op2Input;
std::getline(std::cin, op2Input);
// TODO: Разобрать данные клиента из customerInput
// Подсказка: Используйте find(',') для разделения строки
// TODO: Разобрать данные счёта из accountInput
// TODO: Создать банк
// TODO: Создать клиента
// TODO: Создать сберегательный счёт с клиентом в качестве владельца
// TODO: Добавить счёт клиенту
// TODO: Добавить клиента в банк
// TODO: Разобрать и обработать операцию 1
// Формат: action,accountNumber,amount (action — это "deposit" или "withdraw")
// TODO: Разобрать и обработать операцию 2
// Может быть: action,accountNumber,amount ИЛИ freeze,accountNumber
// Если freeze, заморозить счёт, затем попытаться снять $10
// TODO: Вывести список счетов клиента
// TODO: Print transaction count as "Transactions: [count]"
return 0;
}
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнерПотренируйтесь самостоятельно: Онлайн-компилятор C++