Перейти к основному содержимому

ООП

Объектно-ориентированное программирование (ООП) — это парадигма программирования, основанная на представлении программы как набора взаимодействующих объектов.

Объект — это структура данных (набор взаимосвязанных полей), которая может быть дополненна каким-то поведением (связанными функциями — методами).

Класс — это шаблон, определяющий структуру данных (поля) и поведение (методы) для множества однотипных объектов.

Основные принципы ООП

Инкапсуляция

Это размещение в одном компоненте данных и методов, которые с ними работают, и реализация механизма управления данными, в частности сокрытие внутренней реализации объекта.

Инкапсуляция нужна для защиты внутреннего состояния объекта от неконтролируемого изменения и уменьшения связности между компонентами программы.

Наследование

Это возможность создания нового класса на основе существующего, когда дочерний класс автоматически перенимает (наследует) поля и методы родительского класса.

Наследование позволяет переиспользовать код и строить на основе этого иерархии классов.

Полиморфизм

Это способность объектов с одинаковым интерфейсом выполнять разные действия в зависимости от их конкретного типа.

Наследование позволяет достигать гибкости и расширяемости кода.

Абстракция

Это моделирование только тех характеристик объекта, которые существенны для текущей задачи, и игнорирование несущественных деталей.

В коде

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

Основные модификаторы доступа:

  • public: поле доступно везде
  • private: поле доступно только внутри своего класса
  • protected: поле доступно внутри своего класса и в наследуемых классах
class Database {
public dialect: string;
private connectionString: string;
}

Полиморфизм обычно реализуется через механизм переопределения функций и методов (overriding) и работу со ссылками базового типа.

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

interface Playable {
play(): void;
}
class VideoPlayer implements Playable {
public play(): void { /* video */ }
}
class AudioPlayer implements Playable {
public play(): void { /* audio */ }
}

Особые методы:

  • конструктор: выполняется при создании объекта
  • деструктор: выполняется при удалении объекта из памяти
  • геттер (getter): выполняется при обращении к полю
  • сеттер (setter): выполняется при изменении поля
  • абстрактный: метод без реализации (только название и аргументы)
  • статический: без доступа к состоянию объекта, связан напрямую с классом

Абстрактный класс — это класс, в котором присутствуют абстрактные методы. При наследовании от абстрактного, дочерний класс должен реализовать абстракции.

Статические методы обычно используются для удобной композиции функций, причастных к данному классу.

class XElement {
public static parse(input: string): XElement {}
public static tryParse(input: string): XElement | null {}
}

Агрегация и композиция

Кроме наследования, связь между классами может проявляться в виде ассоциации, когда один класс включает в себя другой в качестве одного из полей. Это отношение вида "часть-целое".

Агрегация — это отношение, при котором объект содержит внутри себя другие объекты, но они могут существовать независимо.

  • части могут принадлежать нескольким объектам одновременно
  • части создаются и уничтожаются независимо
  • обычно реализуется через передачу объектов извне
class Driver {
constructor(public readonly name: string) {}
}
class Car {
constructor(private readonly driver: Driver) {}
}

const driver = new Driver('John');
const car1 = new Car(driver);
const car2 = new Car(driver);

Композиция — это отношение, где части не могут существовать независимо от целого, т.е. внутренний класс не существует отдельно от основного.

  • владение: внутренние объекты принадлежат основному
  • жизненный цикл частей управляется целым
  • внутренние объекты создаются внутри конструктора основного класса
class Car {
private readonly engine: Engine;
constructor() { this.engine = new Engine(); }
}

const car = new Car();