#include <functional>
#include <iostream>
#include <vector>
#include "account.h"
#include "deposit_feature.h"
#include "interest_feature.h"
#include "withdraw_feature.h"
void ShowBalance(const char prefix, const std::unique_ptr<Account> &account)
{
std::cout << prefix << " Balance (" << account->GetId()
<< "): " << account->GetBalance() << " EUR\n";
}
void CreateAccounts(std::vector<std::unique_ptr<Account>> *accounts)
{
auto deposit_account = std::make_unique<Account>("0001");
deposit_account->AddFeature<DepositFeature>();
accounts->push_back(std::move(deposit_account));
auto deposit_interest_account = std::make_unique<Account>("0002");
deposit_interest_account->AddFeature<DepositFeature>();
deposit_interest_account->AddFeature<InterestFeature>(0.0025);
accounts->push_back(std::move(deposit_interest_account));
auto deposit_interest_withdraw_account = std::make_unique<Account>("0003");
deposit_interest_withdraw_account->AddFeature<DepositFeature>();
deposit_interest_withdraw_account->AddFeature<InterestFeature>(0.001);
deposit_interest_withdraw_account->AddFeature<WithdrawFeature>();
accounts->push_back(std::move(deposit_interest_withdraw_account));
auto deposit_withdraw_account = std::make_unique<Account>("0004");
deposit_withdraw_account->AddFeature<DepositFeature>();
deposit_withdraw_account->AddFeature<WithdrawFeature>();
accounts->push_back(std::move(deposit_withdraw_account));
}
template <class T>
void Process(const std::vector<std::unique_ptr<Account>> &accounts,
std::function<void(std::shared_ptr<T>)> action)
{
for (auto &account : accounts) {
auto prefix = '-';
const auto feature = account->GetFeature<T>();
if (feature != nullptr) {
action(feature);
prefix = '+';
}
ShowBalance(prefix, account);
}
}
void Deposit(const std::vector<std::unique_ptr<Account>> &accounts)
{
auto counter = 0;
Process<DepositFeature>(accounts, [&counter](auto feature) {
feature->Deposit(4200.23 + counter++);
});
}
void PayInterest(const std::vector<std::unique_ptr<Account>> &accounts)
{
Process<InterestFeature>(accounts,
[](auto feature) { feature->PayInterest(); });
}
void Withdraw(const std::vector<std::unique_ptr<Account>> &accounts)
{
Process<WithdrawFeature>(accounts,
[](auto account) { account->Withdraw(10.0); });
}
int main()
{
std::vector<std::unique_ptr<Account>> accounts;
std::cout.precision(2);
std::cout.setf(std::ios_base::fixed);
std::cout << "Create accounts ...\n";
CreateAccounts(&accounts);
std::cout << "\n\nDeposit ...\n";
Deposit(accounts);
std::cout << "\n\nPay interest ...\n";
PayInterest(accounts);
std::cout << "\n\nWithdraw ...\n";
Withdraw(accounts);
return 0;
}
#ifndef ACCOUNT_H_
#define ACCOUNT_H_
#include <map>
#include <memory>
#include <string>
#include "account_feature.h"
class Account final {
protected:
double balance_;
private:
std::string id_;
std::map<std::string, std::shared_ptr<AccountFeature>> features_;
public:
explicit Account(std::string id) noexcept;
template <class T>
void AddFeature();
template <class T, class TParam>
void AddFeature(TParam parameter);
template <class T>
void AddFeature(std::shared_ptr<T> t);
template <class T>
std::shared_ptr<T> GetFeature();
double GetBalance() const noexcept;
void SetBalance(double amount) noexcept;
std::string GetId() const noexcept;
};
template <class T>
void Account::AddFeature()
{
auto t = std::make_shared<T>(this);
AddFeature(t);
}
template <class T, class TParam>
void Account::AddFeature(TParam parameter)
{
auto t = std::make_shared<T>(this, parameter);
AddFeature(t);
}
template <class T>
void Account::AddFeature(std::shared_ptr<T> t)
{
const auto id = typeid(T).name();
const auto iterator = features_.find(id);
if (iterator != features_.end()) {
throw std::runtime_error("Feature already registered");
}
features_[id] = t;
}
template <class T>
std::shared_ptr<T> Account::GetFeature()
{
const auto id = typeid(T).name();
const auto iterator = features_.find(id);
if (iterator != features_.end()) {
return std::static_pointer_cast<T>(iterator->second);
}
return nullptr;
}
#endif // ACCOUNT_H_
#include "account.h"
#include <utility>
Account::Account(std::string id) noexcept : balance_{0.0}, id_{std::move(id)} {}
double Account::GetBalance() const noexcept { return balance_; }
void Account::SetBalance(const double amount) noexcept { balance_ = amount; }
std::string Account::GetId() const noexcept { return id_; }
#ifndef ACCOUNT_FEATURE_H_
#define ACCOUNT_FEATURE_H_
class Account;
class AccountFeature {
protected:
Account* account_;
public:
explicit AccountFeature(Account* account) noexcept;
};
#endif // ACCOUNT_FEATURE_H_
#include "account_feature.h"
AccountFeature::AccountFeature(Account* account) noexcept : account_(account) {}
#ifndef DEPOSIT_FEATURE_H_
#define DEPOSIT_FEATURE_H_
#include "account_feature.h"
class DepositFeature : public AccountFeature {
public:
using AccountFeature::AccountFeature;
void Deposit(double amount) const noexcept;
};
#endif // DEPOSIT_FEATURE_H_
#include "deposit_feature.h"
#include "account.h"
void DepositFeature::Deposit(const double amount) const noexcept
{
if (amount > 0) {
auto balance = account_->GetBalance();
balance += amount;
account_->SetBalance(balance);
}
}
#ifndef INTEREST_FEATURE_H_
#define INTEREST_FEATURE_H_
#include "account_feature.h"
class InterestFeature : public AccountFeature {
private:
double interest_rate_;
public:
explicit InterestFeature(Account* account,
double interest_rate = 0.0) noexcept;
double GetInterestRate() const noexcept;
void SetInterestRate(double interest_rate) noexcept;
void PayInterest() const noexcept;
};
#endif // INTEREST_FEATURE_H_
#include "interest_feature.h"
#include "account.h"
InterestFeature::InterestFeature(Account* account,
const double interest_rate) noexcept
: AccountFeature(account), interest_rate_{interest_rate}
{
}
double InterestFeature::GetInterestRate() const noexcept
{
return interest_rate_;
}
void InterestFeature::SetInterestRate(const double interest_rate) noexcept
{
interest_rate_ = interest_rate;
}
void InterestFeature::PayInterest() const noexcept
{
auto balance = account_->GetBalance();
const auto interest = balance * interest_rate_;
balance += interest;
account_->SetBalance(balance);
}
#ifndef WITHDRAW_FEATURE_H_
#define WITHDRAW_FEATURE_H_
#include "account_feature.h"
class WithdrawFeature : public AccountFeature {
public:
using AccountFeature::AccountFeature;
void Withdraw(double amount) const noexcept;
};
#endif // WITHDRAW_FEATURE_H_
#include "withdraw_feature.h"
#include "account.h"
void WithdrawFeature::Withdraw(const double amount) const noexcept
{
if (amount > 0 && amount < account_->GetBalance()) {
auto balance = account_->GetBalance();
balance -= amount;
account_->SetBalance(balance);
}
}