Рубрики
2. Open-closed principle SOLID

SOLID «EXAMPLE» класс оружие Weapon

  • создаём оружие, которое будет меч
    с определённым типом, уроном и дистанцией
  • создаём персонажа и передаём ему созданный меч
const sword = new Weapon('sword',15,2);
const character = new Character('Warrior',sword);

В классе оружие Weapon мы добавляем новый метод attack

class Weapon {
 type: string;
 damage: number; // 0 - 100;
 range: number; // 0 - 100;

 contructor(type: string, damage: number, range: number) {
  this.type = type;
  this.damage  = damage;
  this.range = range;
 }
 новый метод attack просто имитация
 выводит что-то в консольлог
 attack(){
  console.log('Удар мечом с уроном '+ this.damage);
 }
}

в классе персонаж Character
мы делегируем метод из класса оружие Weapon

class Character {
 name: string;
 weapon: Weapon;

 contructor(name: string, weapon: Weapon) {
  this.name = name;
  this.weapon= weapon;
 }
 принимает оружие
 changeWeapon(newWeapon:Weapon) {
  this.weapon = newWeapon;
 }
 делегируем метод из класса оружие Weapon
 attack(){
  this.weapon.attack();
 }
}

вызываем метод attack
у оружия Weapon через персонажа Character

const sword = new Weapon('sword',15,2);
const character = new Character('Warrior',sword);
character.attack();

создаём новое оружие арбалет crossbow
меняем это оружие у нашего персонажа

получаем результат два раза с разным уроном

  • Удар мечом с уроном 15
  • Удар мечом с уроном 40
const sword = new Weapon('sword',15,2);
const character = new Character('Warrior',sword);
character.attack();

const crossbow = new Weapon('crossbow',40,100);
character.changeWeapon(crossbow);

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

class Weapon {
 type: string;
 damage: number; // 0 - 100;
 range: number; // 0 - 100;

 contructor(type: string, damage: number, range: number) {
  this.type = type;
  this.damage  = damage;
  this.range = range;
 }
 attack(){
  if(this.type === 'sword') {
   console.log('Удар мечом с уроном'+ this.damage');
  }
  if(this.type === 'crossbow') {
   console.log('Выстрел из арбалета с уроном '+ this.damage');
  }
 }
}

выносим метод attack в интерфейс Attacker
чтобы мы могли его переиспользовать в каком-то другом классе

interface Attacker {
 attack: () => void;
}


class Weapon implements Attacker{
 type: string;
 damage: number; // 0 - 100;
 range: number; // 0 - 100;

 contructor(type: string, damage: number, range: number) {
  this.type = type;
  this.damage  = damage;
  this.range = range;
 }
 attack(){}
}
  • создаём конкретный класс Sword которое наследуется от класса оружие Weapon
  • создаём конкретный класс Crossbow которое наследуется от класса оружие Weapon
class Sword extends Weapon {
 attack(){
  console.log('Удар мечом с уроном '+ this.damage');
 }
}
class Crossbow extends Weapon {
 attack(){
  console.log('Выстрел из арбалета с уроном '+ this.damage');
 }
}

В классе оружие Weapon
можем избавится от поля тип type:string

class Weapon {
 type: string;
 damage: number; // 0 - 100;
 range: number; // 0 - 100;

 contructor(type: string, damage: number, range: number) {
  this.type = type;
  this.damage  = damage;
  this.range = range;
 }
}

Теперь чтобы добавить новый вид вооружения

  • Нам достаточно создать класс
  • Наследовать класс от базового класса оружие Weapon
const sword = new Sword(15,2);
const character = new Character('Warrior',sword);
character.attack();

const crossbow = new Weapon(40,100);
character.changeWeapon(crossbow);
character.attack();

Когда продумываете схему ваших сущностей
стоит подумать о том заранее, что вам придётся добавлять какой-то новый функционал и сразу это делать так, чтобы не костылили с куча условий, а делали это путем расширения

Если мы хотим добавить класс нож Knife
то нам не надо тестировать
классы меч Sword и арбалет Character

class Knife extends Weapon {
 attack(){
  console.log('Удар ножом с уроном '+ this.damage');
 }
}

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *