假设我有一个函数Farm (animal1, animal2, ...)
,它将对象作为参数。这些物体要么是绵羊,要么是奶牛,它们是由两种工厂方法之一制成的:
function Sheep(id)
{
function noise() {console.log('baa');}
return {
my_id : id,
noise
}
}
function Cow(id)
{
function noise() {console.log('moo');}
function swish_tail () {}
return {
my_id : id,
noise,
swish_tail
}
}
现在,想象一下,Farm
需要根据每种动物的对象类型做一些不同的事情(例如,只列出每种的数量,或者可能让所有的羊先发出声音,然后让奶牛发出声音(。最好的做法是什么?
- 为每只动物使用原型,并在Farm中检查每只动物的原型
- 基于只有
Cow
作为成员具有swish_tail ()
功能的知识进行工作 Sheep
和Cow
是否在功能上继承了Animal
工厂方法,并向Animal
添加了类似type
成员的内容
理想情况下,Farm
应尽可能不了解每种动物的实施情况,
编辑:我知道这个问题有相似之处,但这并不能完全解决如何解决具体问题的问题。
函数方法是具有type
属性:
const AnimalType = {
SHEEP: 0,
COW: 1
};
function Sheep(id)
{
function noise() {console.log('baa');}
return {
type : AnimalType.SHEEP,
my_id : id,
noise
};
}
function Cow(id)
{
function noise() {console.log('moo');}
function swish_tail () {}
return {
type : AnimalType.COW,
my_id : id,
noise,
swish_tail
};
}
然后你可以检查像这样的动物的类型:
function doSomethingWithAnimal(animal)
{
switch (animal.type) {
case AnimalType.SHEEP:
console.log(`Animal with id ${animal.my_id} is a sheep!`);
break;
case AnimalType.COW:
console.log(`Animal with id ${animal.my_id} is a cow!`);
animal.swish_tail();
}
}
添加一个"类型";到CCD_ 12实例就足够了。下面是我为您做的一个例子,我希望它对理解继承有帮助:
/////////////////////////////////////////
// Create Farm Constructor
function Farm(params) {
this.animals = {} // to be filled with arrays by animal's type
}
Farm.prototype = {
addAnimal( newAnimal ) {
const exists = this.getAnimalById(newAnimal?.id)
if( exists ) {
console.warn('already exists')
return 'already exists'
}
if( !(newAnimal instanceof Animal) ) {
console.warn('not an animal')
return
}
// add new animal to the object containing all animals by type, if not already exists
this.animals[newAnimal.type] = [...(this.animals[newAnimal.type] || []), newAnimal]
},
getAnimalById(id) {
return id && Object.values(this.animals)?.flat()?.includes(id)
},
addAnimals( animals ){
animals.forEach(animal => animal && myFarm.addAnimal(animal))
},
getAnimalsByType( type ) {
return type && this.animals.filter(animal => animal.type == type)
},
listAnimalsSounds( ...types ) {
types = types || Object.keys(this.animals);
for( let type of types ) {
console.log( this.animals[type]?.[0]?.getSound(type) )
}
}
}
/////////////////////////////////////////
// Create Generic-Animal Constructor
function Animal({id, type, name, gender}) {
this.id = id
this.type = type
this.name = name
this.gender = gender
return this
}
// all commonanilities between animals
Animal.prototype = {
getSound(type){
return this.sound
? `${this.sound} is the sound of a ${type}`
: `${type} does not make any sound`
}
}
/////////////////////////////////////////
// Create Cow Animal Constructor
function Cow({name, id, gender, givesMilk}){
Animal.call(this, {id, type: 'cow', name, gender})
this.givesMilk = givesMilk // property specific to cows
return this
}
Cow.prototype = Object.create(Animal.prototype);
Object.assign(Cow.prototype, {
sound: 'moooo',
tail: true,
furr: true,
})
/////////////////////////////////////////
// Create Dog Animal Constructor
function Dog({name, id, gender, knowsTricks}){
Animal.call(this, {id, type: 'dog', name, gender})
this.knowsTricks = knowsTricks // property specific to dogs
return this
}
Dog.prototype = Object.create(Animal.prototype);
Object.assign(Dog.prototype, {
sound: 'howwww',
swim: true,
tail: true,
furr: true,
})
/////////////////////////////////////////
// create a new farm instance and fill with animals
const myFarm = new Farm();
// create initial animals
const cows = [
new Cow({name:'bill', id:11, gender:'male'}),
new Cow({name:'mandy', id:12, gender:'female', givesMilk: true}),
]
const dogs = [
new Dog({name:'ralf', id:21, gender:'male', knowsTricks: false}),
]
// add all initial animals
myFarm.addAnimals([...cows, ...dogs])
// list below animals' sounds, in this order:
myFarm.listAnimalsSounds('dog', 'cow')