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 = 20this.conditionersAmount = 20this.hairSerumsAmount = 1000}checkInventory(product){let available = true;if(product.productName == "shampoo" && product.amount > this.shampoosAmount){available = falsereturn available}else if(product.productName == "conditioner" && product.amount > this.conditionersAmount){available = falsereturn available}else if(product.productName == "hair serum" && product.amount > this.hairSerumsAmount){available = falsereturn 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.