这里正确的功能模式是什么?



假设我有一个函数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 ()功能的知识进行工作
  • SheepCow是否在功能上继承了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')

最新更新