Что такое инкапсуляция в ООП

Ответ

Инкапсуляция — это принцип ООП, который объединяет данные и методы, работающие с ними, в единый объект, скрывая внутренние детали реализации. Это позволяет защитить состояние объекта от неконтролируемого доступа и изменений.

Пример в Node.js с использованием приватных полей:

class BankAccount {
  #balance = 0; // Приватное поле (синтаксис # доступен в Node.js 12+)

  deposit(amount) {
    if (amount > 0) {
      this.#balance += amount;
    } else {
      throw new Error('Deposit amount must be positive');
    }
  }

  withdraw(amount) {
    if (amount > 0 && amount <= this.#balance) {
      this.#balance -= amount;
    } else {
      throw new Error('Invalid withdrawal amount');
    }
  }

  getBalance() {
    return this.#balance;
  }
}

// Использование
const account = new BankAccount();
account.deposit(100);
console.log(account.getBalance()); // 100
// account.#balance - SyntaxError: Private field '#balance' must be declared in an enclosing class

Альтернативный подход (до ES2022) с использованием замыканий:

function createBankAccount() {
  let balance = 0; // "Приватная" переменная в замыкании

  return {
    deposit(amount) {
      if (amount > 0) balance += amount;
    },
    getBalance() {
      return balance;
    }
  };
}

const account = createBankAccount();
account.deposit(50);
console.log(account.getBalance()); // 50
// Прямой доступ к balance отсутствует

Почему это важно в Node.js:

  1. Защита данных: Предотвращает случайное изменение критических данных (баланс, конфигурация)
  2. Гибкость реализации: Можно менять внутреннюю логику, не ломая внешний API
  3. Валидация: Контроль над тем, как данные устанавливаются (например, проверка в deposit())
  4. Согласованность состояния: Гарантирует, что объект всегда находится в валидном состоянии

Ответ 18+ 🔞

Давай разберём эту инкапсуляцию, а то звучит как болезнь какая-то, ёпта. Представь себе банковский счёт. Это же не просто переменная let cash = 100, в которую любой хуй с горы может залезть и написать cash = 1000000. Волнение ебать сразу, правда? Вот чтобы такого не было, и придумали инкапсуляцию — спрятать данные внутрь объекта, как золото в сейф, и выдать только специальные методы-ключи.

Вот смотри, как это в Node.js делается с приватными полями (это современный способ):

class BankAccount {
  #balance = 0; // Вот эта решётка (#) — это и есть наш замок. Поле приватное, снаружи него не видно.

  deposit(amount) {
    if (amount > 0) {
      this.#balance += amount;
    } else {
      throw new Error('Deposit amount must be positive');
    }
  }

  withdraw(amount) {
    if (amount > 0 && amount <= this.#balance) {
      this.#balance -= amount;
    } else {
      throw new Error('Invalid withdrawal amount');
    }
  }

  getBalance() {
    return this.#balance; // Единственная законная дырочка, чтобы посмотреть, сколько там.
  }
}

// Использование
const account = new BankAccount();
account.deposit(100);
console.log(account.getBalance()); // 100
// account.#balance - SyntaxError: Private field '#balance' must be declared in an enclosing class
// Попробуй напрямую поле достать — получишь ошибку, **ни хуя себе**! Вот и вся защита.

А раньше, до этих решёток, народ выкручивался через замыкания — тоже хитрая жопа, но работает. Смысл в том, чтобы переменная жила внутри функции и была недоступна снаружи, как потайной карман.

function createBankAccount() {
  let balance = 0; // Переменная здесь — она как в бункере. Снаружи к ней не подобраться.

  return {
    deposit(amount) {
      if (amount > 0) balance += amount;
    },
    getBalance() {
      return balance;
    }
  };
}

const account = createBankAccount();
account.deposit(50);
console.log(account.getBalance()); // 50
// Попробуй теперь balance найти — нихуя не получится, она в замыкании схоронена.

А зачем это всё, спрашивается, в Node.js?

  1. Защита данных: Чтобы какой-нибудь распиздяй в соседнем модуле не перезаписал твой баланс или конфиг просто по приколу. Доверия ебать ноль в большом проекте.
  2. Гибкость реализации: Сегодня ты хранишь балант в переменной, а завтра захочешь в базе данных или в файле. Меняешь внутренности класса, а все, кто используют deposit() и getBalance(), даже не узнают — их код продолжает работать.
  3. Валидация: Ты можешь вставить проверки в методы. Хочешь положить минус сто рублей? Какого хуя? Метод deposit() тебе этого не позволит, выкинет ошибку. Без инкапсуляции любой мог бы в balance любой пиздец записать.
  4. Согласованность состояния: Объект сам отвечает за свои данные. Не получится создать счёт с отрицательным балансом, потому что метод withdraw() не даст снять больше, чем есть. Всё контролируется в одном месте, а не размазано по всей программе.

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