让我们首先看一个如何在 ES5 中实现继承的示例
class Animal { constructor(name, energy) { this.name = name this.energy = energy } eat(amount) { console.log(`${this.name} is eating.`) this.energy += amount } sleep(length) { console.log(`${this.name} is sleeping.`) this.energy += length } play(length) { console.log(`${this.name} is playing.`) this.energy -= length } } class Dog extends Animal { constructor(name, energy, breed) { super(name, energy) this.breed = breed } bark() { console.log('Woof Woof!') this.energy -= .1 } } class Cat extends Animal { constructor(name, energy, declawed) { super(name, energy) this.declawed = declawed } meow() { console.log('Meow!') this.energy -= .1 } }
我们可以像这样可视化层次结构:
Animal name energy eat() sleep() play() Dog breed bark() Cat declawed meow()
稍后,您的任务是向系统添加另一个实体:用户。
User email username pets friends adopt() befriend() Animal name energy eat() sleep() play() Dog breed bark() Cat declawed meow()
到目前为止一切都很好。然而,您的项目经理现在告诉您也为用户添加吃饭、睡觉和玩耍的功能。你会怎么做?以下是我们在 OOP 中解决这个问题的方法:
Mammal name eat() sleep() play() User email username pets friends adopt() befriend() Animal energy Dog breed bark() Cat declawed meow()
这看起来非常脆弱,因为必须引入另一个实体,随着程序的发展,它现在将具有自己的重要性。这种反模式通常被称为“God Object”。因此,OOP 的问题在于,实体在编写时具有含义,并且可以在以后随着需求的变化而更改。这些更改可能会破坏类层次结构。
我认为缺乏可重用性来自于面向对象的语言,而不是函数式语言。因为面向对象语言的问题是它们带有所有这些隐式环境。你想要一根香蕉,但你得到的是一只拿着香蕉的大猩猩和整个丛林。
——乔·阿姆斯特朗(Erlang 的创建者)
与其思考事物是什么,不如让我们转向事物的作用。
我们可以将它们作为函数并在需要时将它们组合在一起,而不是将这些方法与类紧密耦合。伟大的!那么我们如何对具体的实例进行操作呢?好吧,我们将实例直接传递给我们的函数。闭包让函数记住传递的状态(实例)。
const eater = (state) => ({ eat(amount) { console.log(`${state.name} is eating.`) state.energy += amount } }) const sleeper = (state) => ({ sleep(length) { console.log(`${state.name} is sleeping.`) state.energy += length } }) const player = (state) => ({ play(length) { console.log(`${state.name} is eating.`) state.energy -= length } }) const barker = (state) => ({ bark(length) { console.log(`Woof Woof!`) state.energy -= .1 } }) const meower = (state) => ({ meow(length) { console.log(`Meow!`) state.energy -= .1 } })
狗作为睡眠者、食者、玩家和吠叫者的示例:
function Dog(name, energy, breed) { let dog = { name, energy, breed } return Object.assign( dog, eater(dog), sleeper(dog), player(dog), barker(dog) ) } const dog = Dog('Dog', 10, 'Bulldog') dog.eat(10) dog.bark()
现在用户还可以吃饭、睡觉和玩耍:
function User(email, username) { let user = { email, username, pets: [], friends: [] } return Object.assign( user, eater(user), sleeper(user), player(user) ) }
恭喜,您已经将自己从紧密耦合的继承结构中解放出来。
以上是继承与组合的详细内容。更多信息请关注PHP中文网其他相关文章!