Thursday 18 March 2021

Is inheriting from the EventEmitter an antipattern?

It appears to be common practice to inherit from the EventEmitter if you want your class to support events. For example Google does it for Puppeteer, the WebSocket module does it, mongoose does it, ... just to name a few.

But is this really good practice? I mean sure it looks nice and clean, but from an OOP perspective it seems wrong. For example:

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')
    }
}

would make it seem like Rectangle is an EventEmitter at its core even though the eventing functionality is secondary.

What if you decide that Rectangle now needs to inherit from a new class called Shape?

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}
    }
}

Now you would have to make Shape inherit from the EventEmitter. Even if only one class inheriting from Shape actually needs eventing.

Wouldn't something like this make way more sense?

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)


from Is inheriting from the EventEmitter an antipattern?

No comments:

Post a Comment