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 = namethis.power = power}}function SuperHeroWithSword(superhero){superhero.sword = truesuperhero.hasSword= function(){return `${this.name}'s power is ${this.power}, and he also has a sword now.`}return superhero;}function SuperHeroWithSuperSpeed(superhero) {superhero.superSpeed = truesuperhero.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 = truesuperhero.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 = namethis.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.