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

Ответ

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

Цель инкапсуляции:

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

Реализация в Python:

Python не имеет строгих модификаторов доступа (как public, private, protected в C++ или Java), но использует соглашения и механизм name mangling:

  • Публичные атрибуты/методы: Доступны всем. Объявляются без префиксов.
  • Защищённые атрибуты/методы (_var): По соглашению, предназначены для использования внутри класса и его наследников. Внешний код может получить к ним доступ, но это считается нарушением конвенции.
  • Приватные атрибуты/методы (__var): Python автоматически изменяет имя таких атрибутов (_ClassName__var), что усложняет прямой доступ извне, но не делает его полностью невозможным. Это скорее механизм для предотвращения конфликтов имен в подклассах.

Пример:

class BankAccount:
    def __init__(self, initial_balance: float):
        # Приватный атрибут, доступ к которому контролируется методами
        self.__balance = initial_balance 

    def deposit(self, amount: float):
        if amount > 0:
            self.__balance += amount
            print(f"Депозит {amount}. Новый баланс: {self.__balance}")
        else:
            print("Сумма депозита должна быть положительной.")

    def withdraw(self, amount: float):
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            print(f"Снятие {amount}. Новый баланс: {self.__balance}")
        else:
            print("Недостаточно средств или некорректная сумма для снятия.")

    def get_balance(self) -> float:
        # Публичный метод для контролируемого доступа к балансу
        return self.__balance

# Использование класса
account = BankAccount(1000)
account.deposit(500) # Корректное изменение баланса
account.withdraw(200) # Корректное изменение баланса
print(f"Текущий баланс: {account.get_balance()}")

# Попытка прямого доступа к приватному атрибуту (не рекомендуется)
# print(account.__balance) # Вызовет AttributeError
# print(account._BankAccount__balance) # Технически возможно, но нарушает инкапсуляцию

В этом примере __balance инкапсулирован. Доступ к нему и его изменение происходят только через публичные методы deposit, withdraw и get_balance, которые могут содержать логику проверки и валидации.