从 EventEmitter 继承是一种反模式吗?
Is inheriting from the EventEmitter an antipattern?
如果您希望 class 支持事件,从 EventEmitter 继承似乎是常见的做法。
例如 Google 为 Puppeteer, the WebSocket module does it, mongoose does it 执行此操作,...仅举几例。
但这真的是好做法吗?我的意思是确保它看起来漂亮干净,但从 OOP 的角度来看它似乎是错误的。例如:
const EventEmitter = require('events')
class Rectangle extends EventEmitter {
constructor(x,y,w,h) {
super()
this.position = {x:x, y:y}
this.dimensions = {w:w, h:h}
}
setDimensions(w,h) {
this.dimensions = {w:w, h:h}
this.emit('dimensionsChanged')
}
}
会让人觉得 Rectangle 的核心是 EventEmitter,尽管事件功能是次要的。
如果您决定 Rectangle
现在需要从一个名为 Shape
的新 class 继承怎么办?
class Shape {
constructor(x,y) {
this.position = {x:x, y:y}
}
}
class Rectangle extends Shape {
constructor(x,y,w,h) {
super(x,y)
this.dimensions = {w:w, h:h}
}
}
现在您必须 Shape
从 EventEmitter 继承。即使只有一个 class 继承自 Shape
实际上需要事件处理。
这样的事情不是更有意义吗?
class Shape {
constructor(x,y) {
this.position = {x, y}
}
}
const EventEmitter = require('events')
class Rectangle extends Shape {
constructor(x,y,w,h) {
super(x,y)
this.dimensions = {w, h}
this.em = new EventEmitter()
}
setDimensions(w,h) {
this.dimensions = {w:w, h:h}
this.em.emit('dimensionsChanged')
}
}
const rectangle = new Rectangle(1,2,3,4)
rectangle.em.on('dimensionsChanged', ()=>{console.log('dimensions changed')})
rectangle.setDimensions(10,20)
是的,这绝对更有意义。
继承应该用来表示是一个关系:class Rectangle extends Shape
是可以的,因为Rectangle
是一个形状,但是这里的矩形本身 不是 EventEmitter
.
相反,我们有一个 can 关系:Rectangle
can emit an event,这正是你应该支持 composition over inheritance,这就是您上一个代码片段中发生的情况。
我们只能推测为什么一些著名的库不这样做——追溯兼容性、API 的简单性,或者仅仅是糟糕的设计。
如果您希望 class 支持事件,从 EventEmitter 继承似乎是常见的做法。 例如 Google 为 Puppeteer, the WebSocket module does it, mongoose does it 执行此操作,...仅举几例。
但这真的是好做法吗?我的意思是确保它看起来漂亮干净,但从 OOP 的角度来看它似乎是错误的。例如:
const EventEmitter = require('events')
class Rectangle extends EventEmitter {
constructor(x,y,w,h) {
super()
this.position = {x:x, y:y}
this.dimensions = {w:w, h:h}
}
setDimensions(w,h) {
this.dimensions = {w:w, h:h}
this.emit('dimensionsChanged')
}
}
会让人觉得 Rectangle 的核心是 EventEmitter,尽管事件功能是次要的。
如果您决定 Rectangle
现在需要从一个名为 Shape
的新 class 继承怎么办?
class Shape {
constructor(x,y) {
this.position = {x:x, y:y}
}
}
class Rectangle extends Shape {
constructor(x,y,w,h) {
super(x,y)
this.dimensions = {w:w, h:h}
}
}
现在您必须 Shape
从 EventEmitter 继承。即使只有一个 class 继承自 Shape
实际上需要事件处理。
这样的事情不是更有意义吗?
class Shape {
constructor(x,y) {
this.position = {x, y}
}
}
const EventEmitter = require('events')
class Rectangle extends Shape {
constructor(x,y,w,h) {
super(x,y)
this.dimensions = {w, h}
this.em = new EventEmitter()
}
setDimensions(w,h) {
this.dimensions = {w:w, h:h}
this.em.emit('dimensionsChanged')
}
}
const rectangle = new Rectangle(1,2,3,4)
rectangle.em.on('dimensionsChanged', ()=>{console.log('dimensions changed')})
rectangle.setDimensions(10,20)
是的,这绝对更有意义。
继承应该用来表示是一个关系:class Rectangle extends Shape
是可以的,因为Rectangle
是一个形状,但是这里的矩形本身 不是 EventEmitter
.
相反,我们有一个 can 关系:Rectangle
can emit an event,这正是你应该支持 composition over inheritance,这就是您上一个代码片段中发生的情况。
我们只能推测为什么一些著名的库不这样做——追溯兼容性、API 的简单性,或者仅仅是糟糕的设计。