Challenge: Solution Review

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

We'll cover the following

Solution #

class SuperHero {
constructor(name,power) {
this.name = name
this.power = power
}
}
function SuperHeroWithSword(superhero){
superhero.sword = true
superhero.hasSword= function(){
return `${this.name}'s power is ${this.power}, and he also has a sword now.`
}
return superhero;
}
function SuperHeroWithSuperSpeed(superhero) {
superhero.superSpeed = true
superhero.hasSuperSpeed= function(){
return `${this.name}'s power is ${this.power}, and he also has the super speed now.`
}
return superhero;
}
function SuperHeroWithSpeedandSword(superhero){
superhero.speedAndSword = true
superhero.hasSpeedAndSword = function(){
return `${this.name}'s power is ${this.power}, and he also has both super speed and a sword now.`
}
return superhero;
}
var superhero1 = new SuperHero("Fire Man", "Fire")
SuperHeroWithSword(superhero1)
console.log(superhero1.hasSword())
SuperHeroWithSuperSpeed(superhero1)
console.log(superhero1.hasSuperSpeed())
var superhero2 = new SuperHero("Ice Man", "Ice")
SuperHeroWithSpeedandSword(superhero2)
console.log(superhero2.hasSpeedAndSword())

Explanation #

Let’s start by going through the original code, so we can understand how to modify it.

class SuperHero {
constructor(name,power) {
this.name = name
this.power = power
}
}
class SuperHeroWithSword extends SuperHero{
constructor(name,power){
super(name,power)
this.sword = true
}
hasSword(){
return `${this.name}'s power is ${this.power}, and he also has a sword now.`
}
}
class SuperHeroWithSuperSpeed extends SuperHero{
constructor(name,power){
super(name,power)
this.superSpeed = true
}
hasSuperSpeed(){
return `${this.name}'s power is ${this.power}, and he also has the super speed now.`
}
}
class SuperHeroWithSpeedandSword extends SuperHero{
constructor(name,power){
super(name,power)
this.speedAndSword = true
}
hasSpeedAndSword(){
return `${this.name}'s power is ${this.power}, and he also has both super speed and a sword now.`
}
}
var superhero1 = new SuperHeroWithSword("Fire Man", "Fire")
console.log(superhero1.hasSword())
var superhero2 = new SuperHeroWithSuperSpeed("Fire Man", "Fire")
console.log(superhero2.hasSuperSpeed())
var superhero3 = new SuperHeroWithSpeedandSword("Ice Man", "Ice")
console.log(superhero3.hasSpeedAndSword())

You can see that the original code implements inheritance to create a customized character. It has a SuperHero class:

class SuperHero {
  constructor(name,power) {
    this.name = name
    this.power = power
  }
}

Each SuperHero instance will have a name and power. Next, there are three child classes all of which extend the functionality of the SuperHero class:

class SuperHeroWithSword extends SuperHero{
  //code...
}

class SuperHeroWithSuperSpeed extends SuperHero{
   //code...
}

class SuperHeroWithSpeedandSword extends SuperHero{
  //code...
}

The extend keyword allows them to inherit the properties of the parent class, SuperHero. They extend the functionality of the SuperHero class by initializing an additional property and a method in their definitions:

class SuperHeroWithSword extends SuperHero{
    //code....
    this.sword = true
    hasSword(){/*code..*/}
}

class SuperHeroWithSuperSpeed extends SuperHero{
    //code....
    this.superSpeed = true
    hasSuperSpeed(){/*code..*/}
}


class SuperHeroWithSpeedandSword extends SuperHero{
    //code....
    this.speedAndSword = true
    hasSpeedAndSword(){/*code..*/}
}

Since each customization (adding a sword, the speed, or both) is a separate class, a superhero can only have one customization at a time. Let’s look at an example:

var superhero1 = new SuperHeroWithSword("Fire Man", "Fire")

Here superhero1 has a sword; however, for it to have both: a sword and the super speed, it will have to be an object of the SuperHeroWithSpeedandSword class.

In a previous lesson, we discussed that when a program has distinct objects with similar underlying code, it is better to use the decorator pattern rather than creating various sub-classes. This allows us to add multiple functionalities to an object. Similarly, the challenge also requires us to modify the code such that each superhero can have various customizations. We can achieve this using the decorator pattern.

Let’s modify each child class according to the decorator pattern:

function SuperHeroWithSword(superhero){
    superhero.sword = true
    superhero.hasSword= function(){/*code*/}
    return superhero;
} 

function SuperHeroWithSuperSpeed(superhero) {
    superhero.superSpeed = true
    superhero.hasSuperSpeed= function(){/*code*/}
    return superhero;
}

function SuperHeroWithSpeedandSword(superhero){
    superhero.speedAndSword = true
    superhero.hasSpeedAndSword = function() {/*code*/} 
    return superhero;
}

Now, each class is a function that takes the SuperHero object as a parameter, adds new properties/methods to it, and returns it. Hence, it is possible to add various customizations to a superhero now:

var superhero1 = new SuperHero("Fire Man", "Fire")
SuperHeroWithSword(superhero1)
SuperHeroWithSuperSpeed(superhero1)

As you can see, you have the option to add a sword, the super speed, or both to superhero1.


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