Банковская система
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy — урок 104 из 104.
Задание
ЛегкоДавайте создадим банковскую систему, которая демонстрирует паттерн Состояние (State), наследование и управление умными указателями. Вы создадите систему, в которой счета могут находиться в разных состояниях (Active, Frozen, Closed), каждое из которых имеет свои особенности обработки транзакций.
Вы организуете свой код в шести файлах:
AccountState.h: Определите инфраструктуру паттерна Состояние для состояний счета.Создайте абстрактный базовый класс
AccountStateс чисто виртуальными методами:deposit(double amount)— возвращает true, если депозит разрешен, иначе falsewithdraw(double amount)— возвращает true, если снятие разрешено, иначе falsegetStateName()— возвращает название состояния в виде строки
Реализуйте три конкретных состояния:
ActiveState: Разрешает как депозиты, так и снятие средств, возвращает"Active"FrozenState: Разрешает депозиты, но отклоняет снятие средств, возвращает"Frozen"ClosedState: Отклоняет как депозиты, так и снятие средств, возвращает"Closed"
Account.h: Постройте иерархию счетов с управлением состоянием.Создайте базовый класс
Accountс:- Номером счета (string), именем владельца и балансом
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: Имеет лимит овердрафта (передается в конструктор). Позволяет снимать средства в пределах (balance + overdraftLimit). Возвращает"Checking"в качестве типа счета.
Transaction.h: Моделируйте транзакции как объекты.Создайте класс
Transaction, который записывает:- Тип транзакции (string: "Deposit", "Withdrawal", "Transfer")
- Сумму
- Номер задействованного счета
- Статус успеха (bool)
Добавьте метод
getDescription(), возвращающий"[type]: $[amount] on [accountNumber] - [Success/Failed]"Customer.h: Создайте клиента, который владеет несколькими счетами.У
Customerесть имя, ID и вектор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Эта задача объединяет паттерн Состояние для управления поведением счетов, наследование для различных типов счетов, умные указатели для отношений владения и отслеживание транзакций — все основные концепции, которые вы освоили в этом курсе.
Попробуйте сами
#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: Вывести количество транзакций в формате "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Итоги — Обобщенный контейнер