using System.Collections.Generic;
using System.Threading.Tasks;
void AddAccount(IAccount account, string key);
double ProcessTransaction(IAccount account, ITransaction transaction);
double TransferTransaction(ITransaction transaction, IAccount receiver, IAccount sender);
IAccount GetAccount(string key, string code, out bool success);
public abstract class AbstractBank : IBank
public abstract void AddAccount(IAccount account, string key);
public abstract double ProcessTransaction(IAccount account, ITransaction transaction);
public abstract double TransferTransaction(ITransaction transaction, IAccount receiver, IAccount sender);
public abstract IAccount GetAccount(string key, string code, out bool success);
protected abstract IAccount GetAccount(string key, out bool success);
public class Bank : AbstractBank
Dictionary<string, IAccount> accounts = new Dictionary<string, IAccount>();
public override void AddAccount(IAccount account, string key)
if (!accounts.ContainsKey(key))
accounts.Add(key, account);
else Console.WriteLine("Error! An account using key:{0} already exists!", key);
protected override IAccount GetAccount(string key, out bool success)
bool has = accounts.TryGetValue(key, out account);
Console.WriteLine("Error! No account found for key: {0}", key);
public override IAccount GetAccount(string key, string code, out bool success)
Console.WriteLine("Error! Account key does not match code for {1}", code);
return GetAccount(key, out success);
public override double ProcessTransaction(IAccount account, ITransaction transaction)
return transaction.Operate(account);
public override double TransferTransaction(ITransaction transaction, IAccount receiver, IAccount sender)
transaction.Operate(receiver);
return transaction.ReverseOperate(sender);
public List<ITransaction> FindTransaction(IEnumerable<Func<IAccount, ITransaction>> funcList)
List<ITransaction> result = new List<ITransaction>();
foreach (var account in accounts.Values)
foreach (var func in funcList)
ITransaction res = func(account);
if (res != default(ITransaction))
public List<ITransaction> FindTransaction(IEnumerable<Func<IAccount, ITransaction>> funcList, IAccount account)
List<ITransaction> result = new List<ITransaction>();
foreach (var func in funcList)
ITransaction res = func(account);
if (res != default(ITransaction))
private AbstractBank bank;
private ITransaction CreateTransactionDeposit(double amount, DateTime date) { return new TransactionDeposit(amount, date);}
private ITransaction CreateTransactionWithdraw(double amount, DateTime date) { return new TransactionWithdraw(amount, date);}
public static ATM CreateATM(string auth)
public void AddAccount(IAccount account, string key)
bank.AddAccount(account, key);
private double TransferTransaction(ITransaction transaction, IAccount receiver, IAccount sender)
return bank.TransferTransaction(transaction, receiver, sender);
private IAccount GetAccount(string key, string code, out bool success)
return bank.GetAccount(key, code, out success);
public double AuthorizeDeposit(double amount, string key, string code, out bool success)
IAccount account = bank.GetAccount(key, code, out success);
return bank.ProcessTransaction(account, CreateTransactionDeposit(amount, DateTime.Now));
public double AuthorizeWithdraw(double amount, string key, string code, out bool success)
IAccount account = bank.GetAccount(key, code, out success);
return bank.ProcessTransaction(account, CreateTransactionWithdraw(amount, DateTime.Now));
public double AuthorizeTransfer(double amount, string key, string code, out bool success, IAccount targetAccount)
IAccount account = GetAccount(key, code, out success);
return TransferTransaction(CreateTransactionWithdraw(amount, DateTime.Now), targetAccount, account);
private abstract class Transaction : ITransaction
public DateTime Date { get; set; }
public string Description { get; set; }
public double Amount { get; set; }
public abstract double Operate(IAccount account);
public abstract double ReverseOperate(IAccount account);
public Transaction(double amount, string type, DateTime date)
private class TransactionWithdraw : Transaction
public override double Operate(IAccount account)
return account.Withdraw(this);
public override double ReverseOperate(IAccount account)
return account.Deposit(this);
public TransactionWithdraw(double amount, DateTime date) : base(amount, "withdraw", date)
private class TransactionDeposit : Transaction
public override double Operate(IAccount account)
return account.Deposit(this);
public override double ReverseOperate(IAccount account)
return account.Withdraw(this);
public TransactionDeposit(double amount, DateTime date) : base(amount, "deposit", date)
public interface IAccountInfo
string Name { get; set; }
double Balance { get; set; }
List<ITransaction> Transactions { get; set; }
public interface IAccount : IAccountInfo
double TransactionReport();
List<ITransaction> LoadTransactions();
void SetBalance(double value);
double Deposit(ITransaction transaction);
double Withdraw(ITransaction transaction);
public abstract class Account : IAccount
public string Name { get; set; }
public double Balance { get; set; }
public List<ITransaction> Transactions { get; set; }
public abstract double CheckBalance();
public abstract double MonthlyReport();
public abstract double TransactionReport();
public abstract void SaveTransactions();
public abstract List<ITransaction> LoadTransactions();
protected abstract double Withdraw(double amount);
protected abstract double Deposit(double amount);
public abstract void SetBalance(double value);
Transactions = new List<ITransaction>();
public double Deposit(ITransaction transaction)
Transactions.Add(transaction);
return Deposit(transaction.Amount);
public double Withdraw(ITransaction transaction)
Transactions.Add(transaction);
return Withdraw(transaction.Amount);
public class CheckingAccount : Account
public override double CheckBalance()
public override double MonthlyReport()
throw new NotImplementedException();
public override double TransactionReport()
throw new NotImplementedException();
public override void SaveTransactions()
throw new NotImplementedException();
public override List<ITransaction> LoadTransactions()
throw new NotImplementedException();
protected override double Withdraw(double amount)
double currBal = CheckBalance();
SetBalance(currBal - amount);
protected override double Deposit(double amount)
double currBal = CheckBalance();
SetBalance(currBal + amount);
public override void SetBalance(double value)
public class CreditAccount : Account
public override double CheckBalance()
public override double MonthlyReport()
public override double TransactionReport()
public override void SaveTransactions()
throw new NotImplementedException();
public override List<ITransaction> LoadTransactions()
protected override double Withdraw(double amount)
double currBal = CheckBalance();
protected override double Deposit(double amount)
double currBal = CheckBalance();
double finalAMount = currBal - amount;
public override void SetBalance(double value)
public class CashAccount : Account
public override double CheckBalance()
public override double MonthlyReport()
throw new NotImplementedException();
public override double TransactionReport()
throw new NotImplementedException();
public override void SaveTransactions()
throw new NotImplementedException();
public override List<ITransaction> LoadTransactions()
protected override double Withdraw(double amount)
double currBal = CheckBalance();
SetBalance(currBal - amount);
protected override double Deposit(double amount)
double currVal = CheckBalance();
public override void SetBalance(double value)
public interface ITransaction
DateTime Date { get; set; }
string Description { get; set; }
double Amount { get; set; }
double Operate(IAccount account);
double ReverseOperate(IAccount account);
static public void Main(string[] args)
ATM atm = ATM.CreateATM("guestAuth");
IAccount account = new CheckingAccount();
atm.AddAccount(account, key);
Console.WriteLine("balance: " + account.Balance);
atm.AuthorizeDeposit(50.50, key, code, out successfulDeposit);
Console.WriteLine("new balance: " + account.Balance);
Console.WriteLine("count: " + account.Transactions.Count);
IAccount account1 = new CreditAccount();
atm.AddAccount(account1, key1);
Console.WriteLine("balance1: " + account1.Balance);
atm.AuthorizeWithdraw(500.00, key1, code1, out successfulWithdraw);
Console.WriteLine("new balance1: " + account1.Balance);
Console.WriteLine("count1: " + account1.Transactions.Count);
atm.AuthorizeDeposit(800.00, key1, code1, out successfulDeposit);
Console.WriteLine("new balance1: " + account1.Balance);
Console.WriteLine("count1: " + account1.Transactions.Count);
IAccount account2 = new CashAccount();
atm.AddAccount(account2, key2);
atm.AuthorizeDeposit(100.00, key2, code2, out successfulDeposit);
Console.WriteLine("balance2: " + account2.Balance);
double withdraw = atm.AuthorizeWithdraw(50.00, key2, code2, out successfulWithdraw);
Console.WriteLine("withdrawn: {0}", withdraw);
Console.WriteLine("new balance2: " + account2.Balance);
Console.WriteLine("count2: " + account2.Transactions.Count);