jozenbasin
jozenbasin

Reputation: 2552

OOP for multi-component classes

I'm having a very hard time writing modules that are comprised of typically 3-5 smaller modules or classes. The issue arises when these sub components need to be extended, but the main module is already creating and implementing their base versions.

Example

// main module design

class Car {
  constructor() {
    this.horn = new Horn();
    this.horn.on('honk', function() {
      console.log('honked');
    })
  }
}

class Horn {
  constructor() {
    this.sound = 'hornA.wav'
  }
}

// extended module design

class RaceCar extends Car {
  constructor() {
    super();
    this.horn = new RaceHorn();

    // event handler is now missing
  }
}

class RaceHorn extends Horn {
  constructor() {
    super();
    this.horn = 'hornB.wav'
  }
}

This is indeed a very simplified example, while my true issues involve modules with more components and more setup requirements. I do understand that I can put things into another init or setup or similar function, but to me it seems like I'm doing something wrong inherently.

Upvotes: 1

Views: 38

Answers (1)

towc
towc

Reputation: 2034

I heavily suggest passing the values through parameters, for what concerns this issue. Default parameters can help a lot

// main module design

class Car {
  constructor( parametrizedHorn=Horn ) {
    this.horn = new parametrizedHorn();
    this.horn.on('honk', function() {
      console.log('honked');
    })
  }
}

class Horn {
  constructor() {
    this.sound = 'hornA.wav'
  }
}

// extended module design

class RaceCar extends Car {
  constructor() {
    super( RaceHorn );
  }
}

class RaceHorn extends Horn {
  constructor() {
    super();
    this.sound = 'hornB.wav'
  }
}

This can get very messy, so instead you can use initialization methods

// main module design

class Car {
  constructor() { ... }
  init( hornType=Horn ){
    this.initHorn( hornType );
  }
  initHorn( hornType=Horn ){
    this.horn = new Horn();
    this.horn.on('honk', function() {
      console.log('honked');
    })
  }
}

class Horn {
  constructor() {
    this.sound = 'hornA.wav'
  }
}

// extended module design

class RaceCar extends Car {
  constructor() {
    super();
  }
  init( hornType=RaceHorn ){
    this.initHorn( hornType );
  }
}

class RaceHorn extends Horn {
  constructor() {
    super();
    this.sound = 'hornB.wav'
  }
}

const raceCar = new RaceCar();
raceCar.init();

These are two modular patterns that you can use, and depending on the kind of structure you're already using, you can judge which one is best. The trick in the end is to parametrize the contents of your class, or modularize it even further with methods

Upvotes: 1

Related Questions