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

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

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

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

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

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

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

Инкапсуляция — это скрытие внутренней реализации и предоставление контролируемого интерфейса. Покажу реальный пример из gamedev.

Плохая инкапсуляция

public class Player : MonoBehaviour
{
    public int currentHealth = 100;
    public int maxHealth = 100;
    public Vector3 position;
    
    public void TakeDamage(int damage)
    {
        currentHealth -= damage;
    }
}

// Где-то в коде:
player.currentHealth = -500; // Можно установить отрицательное значение!
player.maxHealth = 0; // Можно нарушить инварианты

Хорошая инкапсуляция

public class Player : MonoBehaviour
{
    private int _currentHealth;
    private int _maxHealth;
    private Vector3 _position;
    
    public event System.Action<int> HealthChanged;
    public event System.Action OnDied;
    
    public int CurrentHealth => _currentHealth;
    public int MaxHealth => _maxHealth;
    public float HealthPercent => (float)_currentHealth / _maxHealth;
    public Vector3 Position 
    { 
        get => _position;
        set => _position = value; // Можно добавить логику
    }
    
    public void Initialize(int maxHealth)
    {
        _maxHealth = Mathf.Max(1, maxHealth);
        _currentHealth = _maxHealth;
    }
    
    public void TakeDamage(int damage)
    {
        if (damage < 0) return; // Валидация
        
        int oldHealth = _currentHealth;
        _currentHealth = Mathf.Max(0, _currentHealth - damage);
        
        HealthChanged?.Invoke(_currentHealth);
        
        if (_currentHealth == 0 && oldHealth > 0)
        {
            OnDied?.Invoke();
        }
    }
    
    public void Heal(int amount)
    {
        if (amount < 0) return;
        
        _currentHealth = Mathf.Min(_currentHealth + amount, _maxHealth);
        HealthChanged?.Invoke(_currentHealth);
    }
}

// Использование:
player.TakeDamage(25); // Безопасно
player.CurrentHealth = -500; // Ошибка компилятора!

Преимущества такой инкапсуляции

Контроль над состоянием — здоровье никогда не может быть <0 или >maxHealth

События для оповещения — UI, audio, particles узнают об изменениях без прямой связи

Валидация — плохие значения отклоняются в методе, не в коде

Простота refactoring — если нужна логика регенерации, меняю только Player

Второй пример: Weapon System

public class Weapon
{
    private int _ammo;
    private int _maxAmmo;
    private float _lastFireTime;
    private float _fireRate;
    
    public bool CanFire => Time.time - _lastFireTime >= 1f / _fireRate && _ammo > 0;
    public int CurrentAmmo => _ammo;
    
    public Weapon(int maxAmmo, float fireRate)
    {
        _maxAmmo = maxAmmo;
        _fireRate = fireRate;
        _ammo = maxAmmo;
    }
    
    public bool TryFire()
    {
        if (!CanFire) return false;
        
        _ammo--;
        _lastFireTime = Time.time;
        return true;
    }
    
    public void Reload()
    {
        _ammo = _maxAmmo;
    }
}

Ключевые правила инкапсуляции

  • private — внутреннее состояние скрыто
  • properties — контролируемый доступ через get/set
  • методы — действия, которые меняют состояние правильно
  • события — оповещение без прямой связи
  • валидация — проверка в точке входа

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