JS rozhovor za 2 minuty / Dědičnost v OOP

// Možná by stálo za to si nejprve přečíst předchozí díl
// JS rozhovor za 2 minuty / Objektově orientované programování (OOP)

Otázka:
Co je dědičnost v OOP?

Rychlá odpověď:
Dědičnost je způsob, jak upravit nebo rozšířit rodičovskou třídu v podřízené třídě.

Delší odpověď:
Podívejme se, co máme v předchozím příspěvku, a zkusme to rozšířit.

class DogProfile {
  constructor(name, age) {
    this.name = name
    this.age = age
    this.isGood = true
  }

  bark() {
    alert('Bark!')
  }

  barkInEnglish() {
    alert(`Hello my friend! My name is ${this.name}.`)
  }

  // ...
}

Nyní máme profil pracovního psa, ale co když potřebujeme přidat profil kočky? Bylo by to trochu jiné, protože dobrá nebo špatná terminologie není použitelná pro kočky, ty jsou nad těmito měřeními.

{
  name: 'Fluffer',
  age: 2,
  isFluffer: true,
}

Kopírování a úprava DogProfile class by bylo divné, protože budeme muset udržovat dvě téměř přesné kopie.

Dědictví k záchraně! Můžeme přesunout sdílenou funkcionalitu do nějaké samostatné třídy a prostě zdědit DogProfile a CatProfile z nového BaseProfile třída.

class BaseProfile {
  constructor(name, age) {
    this.name = name
    this.age = age
  }

  setName(name) {
    this.name = name
  }

  setAge(age) {
    this.age = age
  }
}

class DogProfile extends BaseProfile {
  constructor(name, age) {
    super(name, age)
    this.isGood = true
  }

  bark() {
    alert('Bark!')
  }

  barkInEnglish() {
    alert(`Hello my friend! My name is ${this.name}.`)
  }
}

class CatProfile extends BaseProfile {
  constructor(name, age, isFluffer) {
    super(name, age)
    this.isFluffer = isFluffer
  }

  meow() {
    alert('Meow!')
  }
}

const doggert = new DogProfile('Doggert', 2)
doggert.barkInEnglish()

const fluffert = new CatProfile('Fluffert', 2, true)
fluffert.meow()

Úžasné, takhle můžeme vytvořit jakýkoli nový typ profilu bez velkého úsilí a každá nová třída bude mít pouze nová pole a metody, které jsou potřeba.

Aplikace v reálném životě:

Problém s dědičností je, že pokud nenaplánujete několik kroků dopředu, můžete skončit v nepořádku.

Jedním z možných typů problémů je situace, kdy dědičnost ve skutečnosti nepopisuje datové vztahy.

class Duck {
  quack() {}
  fly() {}
}

class Plane extends Duck {
  // Forbidding quacking...
  quack() { throw new Error('DO I LOOK LIKE A DUCK TO YOU?') }
}

Toto nebude příliš spolehlivý Plane létat dál. Představte si, že někdo aktualizuje Duck létat metody s časovým limitem poté, co se unaví. Letadlo se unaví a vrátí se do hnízda také.

Dalším možným problémem je situace, kdy máte složitá data a existuje více než 9000 úrovní vnoření tříd.

// Tohle jsem jednou viděl, bylo to hrozné 😱

class Base {
  constructor(id) { this.id = id }
}

class NamedProfile extends Base { /* ... */ }
class ProfileWithRoles extends NamedProfile { /* ... */ }
class AdminProfile extends ProfileWithRoles { /* ... */ }
// ...
// Things can get much worse if you end up using multiple inheritances without any control
// https://stackoverflow.com/questions/29879267/es6-class-multiple-inheritance/45332959

Existuje způsob, jak si s tímto problémem pohrát pomocí kompozice přes dědičnost nebo pomocí návrhových vzorů. Pokusím se je pokrýt v následujících příspěvcích.

Zdroje:
wiki/OOP
wiki/dědičnost

Další příspěvky:

  • JS rozhovor za 2 minuty / Objektově orientované programování (OOP)
  • JS rozhovor za 2 minuty / statické vs dynamické psaní
  • Rozhovor s JS za 2 minuty / Funkce vyššího řádu

Btw, další zábavné věci zveřejním zde a na Twitteru. Buďme přátelé 👋