Challenge: Solution Review

This lesson will explain the solution to the problem from the last coding challenge.

We'll cover the following

Solution #

Press + to interact
class Command {
execute(args) {};
}
//Withdraw command
class WithDrawAmount extends Command {
constructor(bankaccount) {
super();
this.bankaccount = bankaccount;
}
execute(args) {
this.bankaccount.withdrawMoney(args);
}
}
//CheckAmount command
class CheckAmount extends Command {
constructor(bankaccount) {
super();
this.bankaccount = bankaccount
}
execute() {
this.bankaccount.checkAmount()
}
}
//DepositAmount command
class DepositAmount extends Command {
constructor(bankaccount) {
super();
this.bankaccount = bankaccount
}
execute(args) {
this.bankaccount.depositAmount(args)
}
}
//Invoker
class AccountManager {
request(command,args) {
command.execute(args);
}
}
//Reciever:
class BankAccount {
constructor(amount){
this.amount = amount
}
checkAmount() {
console.log(this.amount)
}
withdrawMoney(withdrawamount) {
if(withdrawamount > this.amount){
console.log("Not enough money")
}
else{
this.amount -= withdrawamount
}
}
depositAmount(money){
this.amount += money
}
}
const manager = new AccountManager();
const account = new BankAccount(100)
const check = new CheckAmount(account);
manager.request(check)
const withdraw = new WithDrawAmount(account);
const deposit = new DepositAmount(account);
manager.request(withdraw,10)
manager.request(check)
manager.request(deposit,50)
manager.request(check)

Explanation #

Let’s start by looking at the original code first:

Press + to interact
class BankAccount {
constructor(amount){
this.amount = amount
}
checkAmount() {
console.log(this.amount)
}
withdrawMoney(withdrawamount) {
if(withdrawamount > this.amount){
console.log("Not enough money")
}
else{
this.amount -= withdrawamount
}
}
depositAmount(money){
this.amount += money
}
}
var account = new BankAccount(100)
account.checkAmount()
account.withdrawMoney(10)
account.checkAmount()
account.depositAmount(50)
account.checkAmount()

In the example, there is a BankAccount class which contains the following functions:

  • checkAmount: return the amount in the account.

  • withdrawMoney: withdraws an amount.

  • depositAmount: deposits an amount.

An account object will directly be able to call on these functions. With the command pattern, we will change that; meaning, the object executing the function will be separated from the one requesting. As mentioned in the question, the command pattern will consist of the following:

  • commands: WithDraw, DepositAmount, and CheckAmount.

  • receiver: BankAccount.

  • invoker: an AccountManager carrying out the operations requested using a request function.

Let’s start by looking at the commands that request some operation on the account.

//Withdraw command
class WithDrawAmount extends Command {/*code*/}

//CheckAmount command
class CheckAmount extends Command {/*code*/} 

//DepositAmount command
class DepositAmount extends Command {/*code*/}

All three commands: WithDrawAmount, CheckAmount, and DepositAmount inherit from the abstract class Command.

class Command {
  execute(args) {};
}

It contains the abstract function execute(args) and each command defines it accordingly.

class WithDrawAmount extends Command {
    
    constructor(bankaccount) {
        super();
        this.bankaccount = bankaccount;
    }
    
    execute(args) {
        this.bankaccount.withdrawMoney(args);
    }
  
}

The constructor of the WithDrawAmount class takes the bankaccount as an argument, using it to initialize the bankaccount property on which it will perform the operation of withdrawing the money. The execute function carries out the operation by calling the withdrawMoney function on the bankaccount.

The constructor for both CheckAmount and DepositAmount are the same as WithDrawAmount. The difference is in the definition of their execute functions.

class CheckAmount extends Command {
 //code...
 execute() {
   this.bankaccount.checkAmount()
  }
}

//DepositAmount command
class DepositAmount extends Command {
   //code...  
   execute(args) {
    this.bankaccount.depositAmount(args)
  }  
}

CheckAmount calls the checkAmount function in the definition of execute and DepositAmount calls the depositAmount function in execute.

We have a BankAccount and we want to send commands to carry out certain operations such as withdrawing, depositing, and checking money. So, how are these commands executed? The AccountManager will be responsible for invoking the operations requested for by the commands.

class AccountManager {
    request(command,args) {
        command.execute(args);
    }
}

When the client sends a command, the AcccountManager processes the request by executing the command and carrying out the required operation. Let’s look at an example:

const account = new BankAccount(100)
const manager = new AccountManager()
const withdraw = new WithDrawAmount(account);
manager.request(withdraw,10)

We have an account and a manager to handle the operations performed on the account. A command to withdraw money is created, and the request to withdraw money is sent to the manager. The manager will carry out the request and the operation will be performed.


Let’s discuss the iterator pattern in the next lesson.