Challenge: Solution Review

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

We'll cover the following

Solution #

class Inventory{
constructor(){
this.shampoosAmount = 20
this.conditionersAmount = 20
this.hairSerumsAmount = 1000
}
checkInventory(product){
let available = true;
if(product.productName == "shampoo" && product.amount > this.shampoosAmount){
available = false
return available
}
else if(product.productName == "conditioner" && product.amount > this.conditionersAmount){
available = false
return available
}
else if(product.productName == "hair serum" && product.amount > this.hairSerumsAmount){
available = false
return available
}
return available
}
}
class BuyingProduct extends Inventory {
buyProduct(product) {
let order;
if(this.checkInventory(product)){
order = new BuyProduct()
}else{
order = new PreOrderProduct()
}
return order.showDetails(product)
}
}
class BuyProduct{
showDetails(product){
console.log(`${product.amount} bottles of ${product.productName} are available. Click on "buy" to purchase them.`)
}
}
class PreOrderProduct{
showDetails(product){
console.log(`${product.amount} bottles of ${product.productName} are not available. You can Pre-order them on the next page.`)
}
}
var customer = new BuyingProduct()
customer.buyProduct({productName: "shampoo", amount: 2})
customer.buyProduct({productName: "hair serum", amount: 2000})

Explanation

Before we delve into the solution, let’s summarize what the challenge is. You have to provide a simple ordering interface to the customer. The implementation should be such that when a customer requests to buy a product, they are displayed whether the product is available for buying or if they need to pre-order it. You have to use the facade pattern here to hide all the background processing that the customer doesn’t need to see.

Now let’s discuss what goes on behind the scenes. We need to implement the following when a product request is made:

  • check whether the product is available or not

  • if available, display a message conveying its availability to the customer

  • if not available, display a corresponding message.

To check whether a product is available or not we defined the Inventory class. As mentioned in the question, it initializes the amounts of hair products. We do that in its constructor as follows:

constructor(){
 this.shampoosAmount = 20
 this.conditionersAmount = 20
 this.hairSerumsAmount = 1000
}

Next, we defined a checkInventory function that checks whether the product requested is available or not. Here’s how we define it:

checkInventory(product){
 let available = true;
 if(product.productName == "shampoo" && product.amount > this.shampoosAmount){
    available = false
    return available
 }
 else if(product.productName == "conditioner" && product.amount > this.conditionersAmount){
     available = false
     return available
 }
 else if(product.productName == "hair serum" && product.amount > this.hairSerumsAmount){
     available = false
     return available
 }
    return available
}

The function is simple; it returns a variable available. If the amount of product bottles requested are greater than those available in the inventory, available is set to false, else it remains true.

So how do we use this function? In the BuyingProduct class, there is a buyProduct function. Since the customer uses this function to buy a product, it should do the following:

  • check if the product is available in the inventory

  • display a corresponding message to the customer depending on the availability of the product

In the buyProduct function, we use the checkInventory method to check for the availability of the product:

class BuyingProduct extends Inventory {
  buyProduct(product) {
    let order;
    if(this.checkInventory(product))  
       order = new BuyProduct()
    }else{
       order = new PreOrderProduct()
    }
  //code...
}

If the product is available, we instantiate an instance of the BuyProduct class; else, we instantiate an instance of the PreOrderProduct class. We store this instance in the order variable. In the end, we invoke the showDetails method on this instance; and return the result of this function.

class BuyingProduct extends Inventory {
  buyProduct(product) {
    let order;
    if(this.checkInventory(product))  
      order = new BuyProduct()
    }else{
      order = new PreOrderProduct()
    }
  return order.showDetails(product)
}

So what is returned from the showDetails method? Since, it is invoked on order this means that this function is defined in both the BuyProduct and PreOrderProduct classes.

class BuyProduct{
  showDetails(product){
    console.log(`${product.amount} bottles of ${product.productName} are available. Click on "buy" to purchase them.`)
  }
}

class PreOrderProduct{
  showDetails(product){
    console.log(`${product.amount} bottles of ${product.productName} are not available. You can Pre-order them on the next page.`)
  }
}

So in the end, the following line in the buyProduct function returns the messages to the customer:

return order.showDetails(product)

There are plenty of ways to solve this problem. The method shown above is just one of the possible solutions. You might also wonder why we need separate BuyProduct and PreOrderProduct classes since we could directly return the messages in the buyProduct function. The reason is that this question implemented only a small part of the ordering system. Further functionalities can be added to both, but to keep the challenge short, we only implemented the showDetails function in them.


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