Как организовать объектно-ориентированный код с помощью наследования

В объектно-ориентированном программировании код часто используется повторно. Существуют классы, так что вы можете создавать объекты без необходимости многократно писать одни и те же переменные и функции.

А как насчет самих классов? Иногда классы тоже очень похожи. Например, у дерева есть ветви, корни и ствол. Это касается вязов, дубов и сосен Пондероза.

Если вы добавляете дерево в игру, вы можете создавать части дерева для десятков деревьев. Но было бы проще создать один древовидный класс, и каждое другое дерево наследовало бы его свойства.

Почему важно наследование?

В объектно-ориентированном программировании есть концепция, которая называется «НЕ СУХИЕ». DRY означает «Не повторяйся». Если вы обнаружите, что копируете и вставляете много кода, вы также создаете место для множества ошибок.

Допустим, вы пишете код для новой игры Тамагочи. Первым виртуальным питомцем станет белый медведь. Итак, вы создаете класс под названием PolarBear в JavaScript / TypeScript.

 class PolarBear {
private _weight: number = 990;
constructor(weight: number = 0) {
this._weight = weight
}
makeNoise() {
console.log("made a roar");
}
eat() {
console.log("eats whatever it wants");
}
sleep() {
console.log("got a good night's sleep");
}
roam() {
console.log("wandered about aimlessly");
}
}

Затем ваш босс говорит вам, что высшее руководство совершило огромный прорыв. Они поняли, что это уже не 90-е, и они могут вместить более 5К памяти в Тамагочи. А теперь они хотят всех медведей.

Вы закатываете рукава и возвращаетесь к работе, создавая копии класса медведя. Затем ваш босс снова стучится в вашу дверь. Оказывается, они хотят, чтобы игра была более познавательной. Теперь вам нужно добавить информацию о происхождении каждого питомца.

Вы больше не дублируете код. Теперь вы меняете сотни строк кода для всех восьми видов медведей. Так случаются ошибки и появляются ошибки.

Пока вы шлифуетесь, ваш босс снова подходит. Теперь высшее руководство хочет, чтобы в игре присутствовали все грызуны. Ах да, жираф.

Вы знаете, что, когда вы закончите, им тоже понадобятся обезьяны или что-то еще. Должен быть способ получше.

Вместо того, чтобы создавать Tamogatchi следующего поколения, вы всегда можете играть с уже существующими .

Наследование на помощь

Чтобы приручить свой виртуальный зверинец, вам нужно быть организованным. Наследование помогает упорядочивать классы, добавляя к ним родительские и дочерние отношения.

Черные медведи, гризли и медведи-ленивцы – все это медведи. Медведи, грызуны и обезьяны – все животные. Вот как мы структурируем наше генеалогическое древо.

Вот как выглядит часть кода:

 class Animal {
private _weight: number;
private _origin: string;
constructor(weight: number = 0, origin: string = "") {
this._weight = weight;
this._origin = origin;
}
makeNoise(noise: string = "") {
console.log("made a noise that sounded like: " + noise);
}
eat(food: string = "") {
console.log("eats " + food);
}
sleep() {
console.log("got a good night's sleep");
}
roam() {
console.log("wandered about aimlessly");
}
}
class Bear extends Animal {
constructor(weight: number, origin: string) {
super(weight, origin);
}
makeNoise(noise: string = "roar") {
super.makeNoise(noise);
}
eat(food: string = "whatever it wants") {
super.eat(food);
}
}
class GrizzlyBear extends Bear {
constructor(weight: number = 600, origin: string = "North America") {
super(weight, origin);
}
}
class Panda extends Bear {
constructor(weight: number = 230, origin: string = "China") {
super(weight, origin);
}
makeNoise() {
super.makeNoise("squeek");
}
eat() {
super.eat("shoots and leaves");
}
}

Вы можете поиграть с кодом в песочнице TypeScript .

Это был большой образец, но код достаточно прост, и все классы происходят от класса Animal . Вы можете видеть, что Медведь расширяет Animal . А GrizzlyBear и Panda расширяют класс Bear . Класс Bear создает функции звука и еды по умолчанию. Класс GrizzlyBear использует эти функции по умолчанию, а Panda – нет.

Другими словами, класс GrizzlyBear не переопределяет функции Bear . Поскольку GrizzlyBear является расширением Bear , он будет использовать функции, определенные Bear автоматически. Но поскольку Panda отменяет функции makeNoise и eat , она будет использовать их вместо них.

Установление взаимоотношений с помощью техники «есть, есть»

Чтобы выяснить, действительно ли класс должен расширять другой класс, вы можете спросить себя, существует ли между ними связь «есть» или «имеет».

  • Лемур «это» обезьяна.
  • Кенгуру «есть» сумчатое животное.
  • Но кроличья лапка – это не кроличья лапка. У кролика лапа.

Этот пример немного упрощен, но при работе с классами реального мира он может быть очень полезным.

Практическая практика и понимание наследования

Готовы применить то, что узнали?

  • Посетите песочницу и заполните остальные классы животных из приведенного выше примера.
  • Добавьте класс Monkey .
  • Добавьте класс ProboscisMonkey, который расширяет ваш класс обезьяны.

Наследование – это больше, чем просто хорошо организованный код. Это основная часть объектно-ориентированного программирования. Наследование помогает упростить связь между объектами. И это позволяет создавать более продвинутый объектно-ориентированный дизайн, например, с полиморфизмом. Вы можете узнать больше о наследовании из документации TypeScript .