Simple bank-account application using composition I'm trying to use composition to design an application that works with different types of bank-accounts. Instead of deriving from a Account Class I want to have separate account classes that are created with appropriate behaviours with a factory. For the example below can I please get some comments on:


Overall design decision
Testability
As i'm adding more behaviours/features does it look sustainable to keep passing objects in constructor? 




#include &lt;iostream&gt;
#include &lt;memory&gt;
#include &lt;string&gt;

using namespace std;

class Balance {
public:
  Balance() {}
  Balance(double amount, std::string currency)
      : d_amount(amount), d_currency(currency) {}
  double amount() const { return d_amount; }
  std::string currency() const { return d_currency; }

private:
  double d_amount;
  std::string d_currency;
};

std::ostream &amp;operator&lt;&lt;(std::ostream &amp;os, const Balance &amp;balance) {
  os &lt;&lt; "Balance-&gt;" &lt;&lt; balance.amount() &lt;&lt; ":Currency-&gt;" &lt;&lt; balance.currency();
  return os;
}

class InterestRate {
private:
  double d_interest_rate;

public:
  virtual double interest_rate() const = 0;
};

class CurrentAccountInterestRate : public InterestRate {
public:
  double interest_rate() const override { return 0.5; }
};

class SavingsAccountInterestRate : public InterestRate {
public:
  double interest_rate() const override { return 2.0; }
};

std::ostream &amp;operator&lt;&lt;(std::ostream &amp;os, const InterestRate &amp;interest_rate) {
  os &lt;&lt; "Interest-Rate-&gt;" &lt;&lt; interest_rate.interest_rate() &lt;&lt; std::endl;
  return os;
}

class CurrentAccount {
public:
  CurrentAccount(const Balance &amp;balance,
                 std::unique_ptr&lt;InterestRate&gt; interest_rate)
      : d_balance(balance), d_interest_rate(std::move(interest_rate)) {}

  void print_balance() { std::cout &lt;&lt; d_balance &lt;&lt; ":" &lt;&lt; *d_interest_rate; }

private:
  Balance d_balance;
  std::unique_ptr&lt;InterestRate&gt; d_interest_rate;
};

class SavingsAccount {
public:
  SavingsAccount(const Balance &amp;balance,
                 std::unique_ptr&lt;InterestRate&gt; interest_rate)
      : d_balance(balance), d_interest_rate(std::move(interest_rate)) {}

  void print_balance() { std::cout &lt;&lt; d_balance &lt;&lt; ":" &lt;&lt; *d_interest_rate; }

private:
  Balance d_balance;
  std::unique_ptr&lt;InterestRate&gt; d_interest_rate;
};

class AccountFactory {
public:
  static CurrentAccount create_current_account(double amount,
                                               const std::string &amp;currency) {
    std::unique_ptr&lt;InterestRate&gt; currentAccountInterestRate =
        std::make_unique&lt;CurrentAccountInterestRate&gt;();
    CurrentAccount ca{Balance{amount, currency},
                      std::move(currentAccountInterestRate)};
    return ca;
  }

  static SavingsAccount create_savings_account(double amount,
                                               const std::string &amp;currency) {
    std::unique_ptr&lt;InterestRate&gt; savingsAccountInterestRate =
        std::make_unique&lt;SavingsAccountInterestRate&gt;();
    SavingsAccount sa{Balance{amount, currency},
                      std::move(savingsAccountInterestRate)};
    return sa;
  }
};

int main() {
  CurrentAccount ca = AccountFactory::create_current_account(20.5, "USD");
  ca.print_balance();
  SavingsAccount sa = AccountFactory::create_savings_account(40.5, "GBP");
  sa.print_balance();
  return 0;
}
Don’t write using namespace std;.

You can, however, in a CPP file (not H file) or inside a function put individual using std::string; etc.  (See SF.7.)



Balance(double amount, std::string currency)
    : d_amount(amount), d_currency(currency) {}

std::string d_currency;


You are taking the currency parameter by value, and then copying it to the member, then you don’t need the first copy anymore.  I think you were trying to use the “sink” parameter idiom?

 : d_amount{amount}, d_currency{std::move(currency)} {}


You forgot the move!  Also, you were using old syntax for the initializers: use uniform initialization style now (since C++11).  (Later) I see you did move in another class, so that was your intent here I think.

I see you are using initializers, which is good.  Likewise, using exactly one of virtual/override/final on a virtual function, and using unique_ptr.



void print_balance() { std::cout &lt;&lt; d_balance &lt;&lt; ":" &lt;&lt; *d_interest_rate; }


That’s exactly the same for CurrentAccount and SavingsAccount.  I thought at first you were overriding a virtual function with no need, but looking closer I see that these classes are not related, and yet they are identical!  I don’t want to do a diff to find out if there is a few chars different somewhere, so that is a concern for understandibility.  

Likewise, AccountFactory is duplicating the same code for both creation functions.  What is the deal here?  If you need “strong types”, just add a template parameter.  Don’t duplicate the entire code for the class manually!



Why is InterestRate a polymorphic interface?  Is what’s shown here just as example, or is there really nothing more to it than different values of a field?  Because in that case, you should just use a value.  This is especially odd since you always use the same Interest Rate class with a corresponding Account class — there is no need to make it polymorphic at all, even if they were really different.