#include <iostream>
#include "bank.h"
#include "ioccontainer.h"
//#define TEST
namespace test {
class Logger : public ILogger {
public:
void Log(const char* message) const override { std::cout << message << "\n"; }
void Log(const char* message, const double value) const override
{
std::cout << message << value << "\n";
}
};
} // namespace test
void PrepareObjects()
{
#ifdef TEST
const auto logger = std::make_shared<test::Logger>();
#else
const auto logger = std::make_shared<Logger>();
#endif
IocContainer::Instance().Register<ILogger>(logger);
}
int main()
{
PrepareObjects();
//Bank bank{std::shared_ptr<ILogger>(new test::Logger{})};
Bank bank{};
auto account1 = bank.OpenCheckingAccount();
auto account2 = bank.OpenSavingsAccount();
return 0;
}
#ifndef ILOGGER_H_
#define ILOGGER_H_
class ILogger {
public:
virtual ~ILogger() = default;
virtual void Log(const char* message) const = 0;
virtual void Log(const char* message, double value) const = 0;
};
#endif // ILOGGER_H_
#ifndef LOGGER_H_
#define LOGGER_H_
#include "ilogger.h"
class Logger : public ILogger {
public:
void Log(const char* message) const override;
void Log(const char* message, double value) const override;
};
#endif // LOGGER_H_
#ifndef ACCOUNT_H_
#define ACCOUNT_H_
#include <memory>
#include "ilogger.h"
class Account {
protected:
const std::shared_ptr<ILogger> logger_;
private:
static double interest_rate_;
double balance_{};
public:
Account();
virtual ~Account() = default;
static double GetInterestRate() noexcept;
static void SetInterestRate(double interest_rate) noexcept;
double GetBalance() const noexcept;
void Deposit(double amount) noexcept;
double Withdraw(double amount) noexcept;
virtual double CalculateInterest() noexcept;
};
#endif // ACCOUNT_H_
#ifndef BANK_H_
#define BANK_H_
#include <list>
#include <memory>
#include "ilogger.h"
class Account;
class Bank {
private:
const std::shared_ptr<ILogger> logger_;
std::list<std::shared_ptr<Account>> accounts_;
public:
Bank();
Bank(std::shared_ptr<ILogger> logger) : logger_{logger} {}
std::shared_ptr<Account> OpenSavingsAccount();
std::shared_ptr<Account> OpenCheckingAccount();
void PayInterest();
private:
std::shared_ptr<Account> OpenAccount(std::shared_ptr<Account> new_account);
};
#endif // BANK_H_
#ifndef CHECKINGACCOUNT_H_
#define CHECKINGACCOUNT_H_
#include "account.h"
class CheckingAccount : public Account {
private:
static double interest_rate_;
public:
static double GetInterestRate() noexcept;
static void SetInterestRate(double interest_rate) noexcept;
double CalculateInterest() noexcept override;
};
#endif // CHECKINGACCOUNT_H_
#ifndef IOCCONTAINER_H_
#define IOCCONTAINER_H_
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <typeinfo>
class IocContainer {
private:
std::map<std::string, std::shared_ptr<void> > objects_;
std::mutex objects_mutex_;
public:
~IocContainer() = default;
IocContainer(const IocContainer&) = delete;
IocContainer(IocContainer&&) = delete;
void operator=(const IocContainer&) = delete;
void operator=(IocContainer&&) = delete;
static IocContainer& Instance();
template <class T>
void Register(std::shared_ptr<T> t);
template <class T>
void Register(const std::string& id, std::shared_ptr<T> t);
template <class T>
std::shared_ptr<T> Resolve();
template <class T>
std::shared_ptr<T> Resolve(const std::string& id);
private:
IocContainer() = default;
};
template <class T>
void IocContainer::Register(std::shared_ptr<T> t)
{
// const auto type_id = &typeid(T);
// Register(type_id->name(), t);
Register(typeid(T).name(), t);
}
template <class T>
void IocContainer::Register(const std::string& id, std::shared_ptr<T> t)
{
std::lock_guard<std::mutex> lock(objects_mutex_);
const auto iterator = objects_.find(id);
if (iterator != objects_.end()) {
throw std::runtime_error("Type already registered");
}
objects_[id] = t;
}
template <class T>
std::shared_ptr<T> IocContainer::Resolve()
{
// const auto type_id = &typeid(T);
// return Resolve<T>(type_id->name());
return Resolve<T>(typeid(T).name());
}
template <class T>
std::shared_ptr<T> IocContainer::Resolve(const std::string& id)
{
std::lock_guard<std::mutex> lock(objects_mutex_);
const auto iterator = objects_.find(id);
if (iterator != objects_.end()) {
return std::static_pointer_cast<T>(iterator->second);
}
throw std::runtime_error("Could not locate type");
}
#endif // IOCCONTAINER_H_
#ifndef SAVINGSACCOUNT_H_
#define SAVINGSACCOUNT_H_
#include "account.h"
class SavingsAccount : public Account {
private:
static double interest_rate_;
public:
static double GetInterestRate() noexcept;
static void SetInterestRate(double interest_rate) noexcept;
double CalculateInterest() noexcept override;
};
#endif // SAVINGSACCOUNT_H_
#include "logger.h"
void Logger::Log(const char* message) const { throw "Not Implemented"; }
void Logger::Log(const char* message, const double value) const
{
throw "Not Implemented";
}
#include "account.h"
#include "logger.h"
#include "ioccontainer.h"
double Account::interest_rate_{};
Account::Account() : logger_{IocContainer::Instance().Resolve<ILogger>()} {}
double Account::GetInterestRate() noexcept { return interest_rate_; }
void Account::SetInterestRate(const double interest_rate) noexcept
{
interest_rate_ = interest_rate;
}
double Account::GetBalance() const noexcept { return balance_; }
void Account::Deposit(const double amount) noexcept
{
balance_ += amount;
logger_->Log("Deposit, balance: ", balance_);
}
double Account::Withdraw(const double amount) noexcept
{
balance_ -= amount;
logger_->Log("Withdraw, balance: ", balance_);
return amount;
}
double Account::CalculateInterest() noexcept { return 0.0; }
#include "bank.h"
#include <ctime>
#include "logger.h"
#include "checkingaccount.h"
#include "ioccontainer.h"
#include "savingsaccount.h"
Bank::Bank() : logger_{IocContainer::Instance().Resolve<ILogger>()} {}
std::shared_ptr<Account> Bank::OpenSavingsAccount()
{
const auto account = std::make_shared<SavingsAccount>();
return OpenAccount(account);
}
std::shared_ptr<Account> Bank::OpenCheckingAccount()
{
const auto account = std::make_shared<CheckingAccount>();
return OpenAccount(account);
}
std::shared_ptr<Account> Bank::OpenAccount(std::shared_ptr<Account> new_account)
{
accounts_.push_back(new_account);
logger_->Log("Create account, number of accounts: ", accounts_.size());
return new_account;
}
void Bank::PayInterest()
{
for (auto& account : accounts_) {
const auto interest = account->CalculateInterest();
account->Deposit(interest);
}
logger_->Log("Interest paid on: ");
time_t current_time;
time(¤t_time);
const auto time_string = ctime(¤t_time);
if (time_string != nullptr) {
logger_->Log(&time_string[0]);
}
}
#include "checkingaccount.h"
#include "logger.h"
double CheckingAccount::interest_rate_{};
double CheckingAccount::GetInterestRate() noexcept { return interest_rate_; }
void CheckingAccount::SetInterestRate(const double interest_rate) noexcept
{
interest_rate_ = interest_rate;
}
double CheckingAccount::CalculateInterest() noexcept
{
const auto interest = GetBalance() * GetInterestRate();
logger_->Log("Calculate interest, amount: ", interest);
return interest;
}
#include "ioccontainer.h"
IocContainer& IocContainer::Instance()
{
static IocContainer instance;
return instance;
}
// sample code how to register an object
// void PrepareObjects()
//{
// const auto logger = std::make_shared<Logger>();
// IocContainer::Instance().Register<ILogger>(logger);
//}
#include "savingsaccount.h"
#include "logger.h"
double SavingsAccount::interest_rate_{};
double SavingsAccount::GetInterestRate() noexcept { return interest_rate_; }
void SavingsAccount::SetInterestRate(const double interest_rate) noexcept
{
interest_rate_ = interest_rate;
}
double SavingsAccount::CalculateInterest() noexcept
{
const auto interest = GetBalance() * GetInterestRate();
logger_->Log("Calculate interest, amount: ", interest);
return interest;
}