Для чего нужны модификаторы видимости в ООП?

Ответ

Модификаторы видимости (public, protected, private) реализуют принцип инкапсуляции — сокрытия внутреннего состояния объекта и деталей реализации от внешнего мира.

Цели:

  1. Защита инвариантов объекта: Предотвращение попадания объекта в неконсистентное состояние извне.
  2. Упрощение интерфейса: Пользователю класса предоставляется только контракт (public методы), скрывая сложную внутреннюю кухню.
  3. Гибкость для изменений: Внутреннюю реализацию (private/protected поля и методы) можно менять, не ломая код, который зависит только от public интерфейса.

Пример на Java/C#-подобном синтаксисе:

class BankAccount {
    // private: Только этот класс имеет прямой доступ.
    // Запрещено менять баланс в обход методов.
    private double balance;
    private String accountNumber;

    // protected: Доступ для этого класса и наследников.
    protected String currency = "USD";

    // public: Интерфейс для внешнего мира.
    public BankAccount(String number, double initialDeposit) {
        this.accountNumber = number;
        this.balance = initialDeposit;
    }

    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount; // Внутренний доступ разрешён
            logTransaction("DEPOSIT", amount);
        }
    }

    public double getBalance() {
        return balance; // Возвращаем копию или значение, но не ссылку на поле
    }

    // private метод: вспомогательная логика, скрытая отвне.
    private void logTransaction(String type, double amount) {
        // Запись в лог...
    }
}

// Использование:
BankAccount acc = new BankAccount("12345", 100.0);
acc.deposit(50.0); // OK
// acc.balance = 1000000; // ОШИБКА КОМПИЛЯЦИИ: поле private
// acc.logTransaction(...); // ОШИБКА: метод private
double currentBalance = acc.getBalance(); // OK, публичный геттер

Ответ 18+ 🔞

А, ну вот, опять про эти ваши модификаторы доступа! Слушай, это ж как в жизни: не всё же показывать первому встречному, правда? Вот представь, у тебя есть кошелёк. Ты же не будешь каждому прохожему кричать: «Смотри, у меня тут пятьсот рублей и карта „Мир“!» Это же пиздец какой-то, сразу налетят гомосеки и всё проебают.

Так вот, эти public, protected, private — они как раз для того, чтобы твой код не превратился в такую вот мартышлюшку, где любая хитрая жопа из другого модуля может влезть и наделать дел.

Зачем это всё, ёпта?

  1. Чтобы не сломать свою же хрень. Допустим, у тебя в классе BankAccount есть поле balance. Если сделать его public, то любой идиот может написать acc.balance = -1000000;. И что? Баланс ушёл в минус на хер, а инвариант про «деньги не могут быть отрицательными» — накрылся медным тазом. А если поле private, то менять его можно только через твои проверяющие методы. Доверия к внешнему коду — ноль ебать, вот и вся философия.
  2. Чтобы не грузить пользователя своей кухней. Представь микроволновку. Тебе же похуй, как там шестерёнки крутятся и магнетрон жужжит? Тебе важен публичный интерфейс: кнопка «Старт», таймер и дверца. Вот и тут так же. Всю внутреннюю пиздопроебибну (private методы вроде logTransaction) прячем, наружу торчит только понятный набор кнопок (public методы deposit, getBalance).
  3. Чтобы можно было всё переписать, не пугая народ. Пока публичный контракт (public методы) работает как обещано, внутри можешь хоть на ассемблере переписать — всем будет похуй. Сегодня balance в double, завтра переведешь на BigDecimal для точности, но геттер getBalance() как возвращал число, так и будет возвращать. Все, кто от тебя зависел, даже не чихнут.

Смотри, как это в коде выглядит, на простом примере:

class BankAccount {
    // private: Вот это прям твоё личное, в душу бога мать.
    // Никакой ушлый чувак извне сюда не влезет и не накосячит.
    private double balance;
    private String accountNumber;

    // protected: Это уже для семьи. Сам доступ есть, и наследнички твои (дочерние классы) тоже могут смотреть.
    protected String currency = "USD";

    // public: А это уже парадная дверь для всех. Входите, не стесняйтесь, но только через неё.
    public BankAccount(String number, double initialDeposit) {
        this.accountNumber = number;
        this.balance = initialDeposit;
    }

    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount; // А внутри-то своего класса — пожалуйста, работай с полями!
            logTransaction("DEPOSIT", amount);
        } else {
            System.out.println("Чувак, ты чё, отрицательные суммы класть? Иди на хуй.");
        }
    }

    public double getBalance() {
        return balance; // Отдаём только копию значения, а не сам нервный центр.
    }

    // private метод: Вспомогательная подлянка, которую никто не должен видеть и вызывать.
    // Типа «записать в лог». Это твоё внутреннее дело.
    private void logTransaction(String type, double amount) {
        // ...какая-то магия с логами...
    }
}

// Использование где-то в другом месте:
BankAccount acc = new BankAccount("12345", 100.0);
acc.deposit(50.0); // Окей, через публичную дверь зашли.
// acc.balance = 1000000; // ОШИБКА КОМПИЛЯЦИИ! Прямой доступ к private полю — низя!
// acc.logTransaction(...); // Тоже ОШИБКА! Это private кухня, тебе там не рады.
double currentBalance = acc.getBalance(); // А так — всегда пожалуйста, вот твой баланс.

Короче, вся суть в том, чтобы разделить: вот это — моё, святое, трогать нельзя (private). Вот это — для моих потомков, чтоб могли дорастить (protected). А вот это — для всех, берите, пользуйтесь, но только так, как я разрешил (public). И тогда будет вам не хиросима, а нормальный, поддерживаемый код, который не развалится от первого же чиха.