Меню

Принцип разделения интерфейса в JavaScript

25.06.2018 - java script, NodeJS, ЯП

Interface Segregation Principle (ISP)

О чем гласит прицип разделения интерфейса?

Класс не должен формировать имплементацию методов, которые никогда не будут использоваться.

Например у нас есть родительский класс IDrawable, у которого два метода: draw() и calculateArea(). От этого класса наследуется класс Shape, от которого наследуются еще два класса: Rectangle и Line.

Как Вы можете заметить у класса Line никак не должно быть метода calculateArea, так как у линий нету площади. Это и есть нарушение этого принципе — класс IDrawable реализует методы, которые не используются некоторыми потомками. Чтобы исправить это, нам нужно разделить интефейсы.

Что такое интерфейс?
Контракт, который заставляет объект или класс реализовать определенную функциональность.

Посмотрим пример.
В общем, есть у нас класс Circle который имеет метод calculateArea, который высчитывает площадь круга. Также есть формула shapeStats, которая выводит площади кругов из массива в консоль. Но у нас есть проблема здесь. Так как мы можем засунуть луюбой тип данных в массив с кругами… например — линию ). Но у линии нету площади! Мы можем вместо этого вычислить например длину у линии. Но это тоже не вариант. Так как мы получим некорректное поведение. В списке площадей выведет длину линии с указанием единиц cm^2.

Хорошим способом исправить это, будет указать условие в функции shapesStats , используя оператор instanceof для определения, является ли текущий объект экземпляром нужного класса. Или просто удалим метод расчёта площади у класса Line, а в функции shapesStats проверим, существует ли функция calculateArea.

class Shape {
  constructor(name) {
    this.name = name;
  }
}

class Circle extends Shape {
  constructor(name, radius) {
    super(name);
    this.radius = radius;
  }

  calculateArea() {
    return Math.PI * this.radius * this.radius;
  }
}

class Line extends Shape {
  constructor(name, pointA, pointB) {
    super(name);
    this.pointA = pointA;
    this.pointB = pointB;
  }

//   calculateArea() {
//     return Math.sqrt(
//       Math.pow(this.pointB.x - this.pointA.x, 2) +
//         Math.pow(this.pointB.y - this.pointA.y, 2)
//     );
//   }
}

function shapeStats(shapes) {
  console.log("Shape stats: ");
  for (let shape of shapes) {
    // if (shape instanceof Circle) {
    if (shape.calculateArea) {
      console.log(`${shape.name} has area of ${shape.calculateArea()}cm^2`);
    }
  }
}

let shapes = [
  new Circle("Circle A", 2),
  new Circle("Circle B", 4),
  new Circle("Circle C", 5),
  new Line("Line A", { x: 1, y: 1 }, { x: 6, y: 7 })
];
shapeStats(shapes);
Метки: , , , ,

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

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