← Назад к вопросам

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

1.6 Junior🔥 111 комментариев
#C# и ООП

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Инкапсуляция в C#

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

Основная идея

Инкапсуляция это упаковка данных и методов в единый класс с ограничением доступа к внутренним данным. Объект контролирует как другие объекты могут его использовать.

// Плохо: прямой доступ к данным
public class BadPlayer {
    public int health = 100;
    public int mana = 50;
}

var player = new BadPlayer();
player.health = -999; // Ой! Отрицательное здоровье
player.mana = 10000; // Ой! Бесконечная мана

// Хорошо: контролируемый доступ
public class GoodPlayer {
    private int health = 100;
    private int mana = 50;
    
    public int GetHealth() => health;
    public int GetMana() => mana;
    
    public void SetHealth(int value) {
        health = Mathf.Clamp(value, 0, 100); // Валидация
    }
    
    public void SetMana(int value) {
        mana = Mathf.Clamp(value, 0, 50);
    }
}

var player = new GoodPlayer();
player.SetHealth(-999); // Будет 0
player.SetMana(10000);  // Будет 50

Модификаторы доступа

private — доступ только внутри класса

public class Account {
    private decimal balance = 1000; // Скрыто от внешнего мира
    
    // Только этот метод может менять баланс
    public void Withdraw(decimal amount) {
        if (amount <= balance) {
            balance -= amount;
        }
    }
}

public — доступ отовсюду

public class Game {
    public void StartGame() {
        // Может быть вызвано откуда угодно
    }
}

protected — доступ в классе и наследниках

public class Character {
    protected int health = 100; // Доступно для наследников
    
    protected virtual void TakeDamage(int damage) {
        health -= damage;
    }
}

public class Warrior : Character {
    public override void TakeDamage(int damage) {
        // Может использовать health
        base.TakeDamage(damage);
    }
}

internal — доступ внутри сборки

internal class DebugHelper {
    // Доступно только внутри проекта
}

Свойства (Properties)

Свойства это более удобный способ контроля доступа к данным.

public class Player {
    private int health = 100;
    
    // Полное свойство
    public int Health {
        get { return health; }
        set { health = Mathf.Max(0, value); }
    }
    
    // Короткое свойство (auto-property)
    public string Name { get; set; }
    
    // Только для чтения
    public int Level { get; private set; }
    
    // С валидацией
    private int mana;
    public int Mana {
        get => mana;
        set => mana = Mathf.Clamp(value, 0, 100);
    }
}

var player = new Player();
player.Health = -50; // Будет 0
player.Name = "Hero";
player.Level = 5; // Ошибка! Это приватный setter

Зачем инкапсуляция?

1. Защита от неправильного использования

public class BankAccount {
    private decimal balance;
    
    public void Deposit(decimal amount) {
        if (amount > 0) {
            balance += amount;
        }
    }
    
    public bool Withdraw(decimal amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            return true;
        }
        return false;
    }
    
    public decimal GetBalance() => balance;
}

// Нельзя прямо мутировать balance
var account = new BankAccount();
account.Deposit(100);
account.Withdraw(50);
// account.balance = -1000; // ОШИБКА! balance приватный

2. Добавление логики без изменения интерфейса

public class Player {
    private int experiencePoints;
    
    public int Experience {
        get => experiencePoints;
        set {
            experiencePoints = value;
            CheckLevelUp(); // Логика при установке
        }
    }
    
    private void CheckLevelUp() {
        if (experiencePoints >= 1000) {
            LevelUp();
        }
    }
}

// Клиент не знает о CheckLevelUp
var player = new Player();
player.Experience = 1500; // Автоматически уровнуется

3. Контроль версионирования

// Версия 1
public class Inventory {
    public List<Item> items; // public
}

// Версия 2: измени реализацию, интерфейс остаётся
public class Inventory {
    private Dictionary<int, Item> items; // Внутри используем словарь
    
    public List<Item> GetItems() => items.Values.ToList();
    public void AddItem(Item item) => items[item.id] = item;
}

// Код клиента работает без изменений
var inventory = new Inventory();
var itemList = inventory.GetItems();

Примеры инкапсуляции в Unity

1. Система здоровья

public class HealthSystem : MonoBehaviour {
    [SerializeField] private int maxHealth = 100;
    private int currentHealth;
    
    public event Action<int> OnHealthChanged;
    
    private void Start() {
        currentHealth = maxHealth;
    }
    
    public int GetHealth() => currentHealth;
    public int GetMaxHealth() => maxHealth;
    public float GetHealthPercent() => (float)currentHealth / maxHealth;
    
    public void TakeDamage(int damage) {
        currentHealth -= damage;
        currentHealth = Mathf.Max(0, currentHealth);
        OnHealthChanged?.Invoke(currentHealth);
        
        if (currentHealth == 0) {
            Die();
        }
    }
    
    public void Heal(int amount) {
        currentHealth += amount;
        currentHealth = Mathf.Min(currentHealth, maxHealth);
        OnHealthChanged?.Invoke(currentHealth);
    }
    
    private void Die() {
        Debug.Log("Character died");
    }
}

// Использование
var healthSystem = GetComponent<HealthSystem>();
if (healthSystem.GetHealth() > 0) {
    healthSystem.TakeDamage(10);
}

2. Система инвентаря

public class Inventory {
    private List<Item> items = new List<Item>();
    public int MaxSlots { get; private set; } = 20;
    
    public int GetItemCount() => items.Count;
    public bool IsFull() => items.Count >= MaxSlots;
    
    public bool AddItem(Item item) {
        if (IsFull()) return false;
        items.Add(item);
        return true;
    }
    
    public bool RemoveItem(Item item) {
        return items.Remove(item);
    }
    
    public Item GetItemAt(int index) {
        if (index >= 0 && index < items.Count) {
            return items[index];
        }
        return null;
    }
    
    public void Clear() {
        items.Clear();
    }
}

Рекомендации

Правило 1: По умолчанию private

public class Player {
    // Приватные по умолчанию
    private int health;
    private int mana;
    private string name;
    
    // Открой только что нужно
    public int GetHealth() => health;
    public void TakeDamage(int damage) => health -= damage;
}

Правило 2: Используй свойства вместо getter/setter методов

// Плохо
public int GetHealth() { return health; }
public void SetHealth(int value) { health = value; }

// Хорошо
public int Health { get; set; }
public int Health { get; private set; }

Правило 3: Валидируй на входе

public class Weapon {
    private int ammo;
    
    public void SetAmmo(int value) {
        ammo = Mathf.Max(0, value); // Валидация
    }
}

Выводы

Инкапсуляция это контроль доступа к данным класса. Позволяет:

  • Защитить данные от неправильного использования
  • Добавлять логику без изменения интерфейса
  • Менять реализацию без влияния на код клиентов
  • Упростить поддержку и отладку кода

Всегда думай: какие данные должны быть приватными, какие публичными, и какие проверки нужны при доступе. Это основа хорошей архитектуры.

Что такое инкапсуляция? | PrepBro