Reputation: 68
I am trying to create a child (sub) class by initiating a parent class with the child type as a parameter, and I am wondering how to do this.
For example, say I have the following starter code:
class Animal{
constructor(settings){
//parent value
this.name = settings.name;
}
//parent function
sayName(){
console.log(`My name is ${this.name}.`);
}
}
class Frog extends Animal{
constructor(settings){
super(settings);
//child-specific value
this.isTreeFrog = settings.isTreeFrog;
}
//child function
livesInTheForest(){
return this.isTreeFrog;
}
}
class Rabbit extends Animal{ [...] }
class Whale extends Animal{ [...] }
I want to be able to write:
let barry = new Animal({
animalType: "frog",
name: "Barry",
isTreeFrog: false
})
(rather than let barry = new Frog({name: "Barry", isTreeFrog: false})
)
and have barry
be a frog, meaning I can write things like this:
barry.sayName() //should print 'My name is Barry'
console.log(barry.livesInTheForest()) //should print 'false'
I have tried two different ways to achieve this, but both are a bit hacky and don't achieve exactly what I want.
The first involves having a value in the Animal class which stores the child in. For example, in the constructor for Animal
I might have something like this:
if(settings.animalType === "frog"){
this.animal = new Frog(settings);
}else [...] //other animal types
There are two main problems with this:
barry.animal.livesInTheForest()
, which creates inconsistency as the parent functions can be called without the .animal
.Frog
) can no longer be child classes, as otherwise I will get too much recursion as it keeps trying to call itself with super().I thought of a second method as well, which works like this:
In the parent (Animal
) constructor:
//make sure this isn't being called from the child class
if(settings.animalType !== null){
if(settings.animalType === "frog"){
//set settings.animal null to avoid too much recursion
//this means that I can't set this.animalType though, so I can't access barry.animalType
settings.animalType = null;
//Is this something I can do?!
this = new Frog(settings);
} else [...] //other animal types
}
This works (I think), but I now can't set this.animalType
to settings.animalType
, meaning I can't write barry.animalType
and get frog
.
Also, this seems really hacky to me and I can't help thinking that there must be a better way to do this.
Upvotes: 0
Views: 1828
Reputation: 1915
class Animal {
static create (settings) {
return new this.subClasses[settings.type](settings)
}
}
class Rabbit extends Animal {}
class Frog extends Animal {}
class Whale extends Animal {}
Animal.subClasses = { frog: Frog, rabbit: Rabbit, whale: Whale }
const animals = ['frog', 'rabbit', 'whale'].map((type) => Animal.create({ type }))
console.log({ animals })
Upvotes: 2