Как стать автором
Поиск
Написать публикацию
Обновить

SOLID для начинающих Unity-разработчиков: простыми словами и с примерами из жизни

Уровень сложностиПростой
Время на прочтение4 мин
Количество просмотров1.3K

Если ты только начал программировать на Unity C#, то наверняка слышал про SOLID.
На каждом собесе спрашивают: "Что такое SOLID? Зачем он нужен? Приведи пример". Но когда ты новичок, кажется, что это что-то сложное и непонятное. Давай разберёмся вместе - просто, по-человечески и с примерами из жизни.


Что такое SOLID?

Вот стандартное описание которое пишут всегда:

SOLID - это пять простых правил, которые помогают писать понятный и удобный код. Если следовать этим правилам, твой проект будет проще поддерживать, дорабатывать и не будет превращаться в кашу.

SOLID - это аббревиатура:

  • S - Single Responsibility Principle (Принцип единственной ответственности)

  • O - Open/Closed Principle (Принцип открытости/закрытости)

  • L - Liskov Substitution Principle (Принцип подстановки Барбары Лисков)

  • I - Interface Segregation Principle (Принцип разделения интерфейса)

  • D - Dependency Inversion Principle (Принцип инверсии зависимостей)


Но зачем все таки нужен SOLID. Чем он помогает. И что вообще это такое?

Когда ты только начинаешь программировать, кажется, что можно просто писать код, и всё будет работать. Но со временем проект растёт, появляются новые фичи, баги, задачи.
Если не соблюдать SOLID, код становится запутанным, его сложно менять, а ошибки появляются всё чаще.

Представь, что ты строишь дом. Сначала всё просто - фундамент, стены, крыша. Но если не следовать правилам строительства, дом быстро начнёт разваливаться: где-то трещина, где-то дверь не закрывается, а если захочешь пристроить балкон - придётся ломать полдома. Так и с кодом: без принципов всё держится на честном слове, и любое изменение может всё сломать.

SOLID - это как инструкция по строительству: если ей следовать, твой проект будет расти без хаоса. Ты сможешь:

  • Легко читать и понимать свой код (даже если вернёшься к нему через месяц или полгода)

  • Быстро добавлять новые фичи, не боясь, что что-то сломается

  • Легко находить и исправлять ошибки

  • Не бояться изменений - твой код будет гибким и устойчивым

  • Работать в команде: другим будет проще разобраться в твоём проекте

Пример из Unity:
Если ты пишешь игру и не следуешь SOLID, то через пару месяцев твой скрипт PlayerController может вырасти до 1000 строк, где намешано всё: движение, стрельба, здоровье, управление UI и даже музыка. Исправить баг или добавить новую механику становится мучением. А если ты разделяешь код по принципам SOLID - каждый скрипт отвечает только за своё, и менять или расширять игру становится легко и приятно.


Примеры из жизни и кода для каждого принципа:

S - Single Responsibility Principle

Один класс - одна ответственность
Один человек - одна задача.

Пример:
В кафе есть бариста, который варит кофе, и повар, который готовит еду. Если бариста начнёт готовить бургеры, а повар - варить кофе, будет бардак. Пусть каждый делает своё дело.

Пример в коде:
// Класс только для движения игрока
public class PlayerMover : MonoBehaviour {
    public void Move(Vector3 direction) {
        transform.Translate(direction);
    }
}

Что происходит в коде:
Класс PlayerMover отвечает только за движение игрока и не занимается ничем другим. Это и есть принцип одной ответственности.


O - Open/Closed Principle

Открыт для расширения, закрыт для изменения
Добавляй новое, не ломая старое.

Пример:
В телефоне можно поставить новое приложение, не перепрошивая всю систему. Так и в коде: добавляешь новую фичу - не трогаешь рабочие части.

Хочешь добавить новый тип врага - не переписывай весь GameManager, а просто добавь новый класс врага.

Пример в коде:
// Базовый класс врага
public abstract class Enemy : MonoBehaviour {
    public abstract void Attack();
}
// Добавляем новый тип врага без изменения существующего кода
public class Zombie : Enemy {
    public override void Attack() { /* ... */ }
}
public class Robot : Enemy {
    public override void Attack() { /* ... */ }
}

Что происходит в коде:
Ты можешь добавлять новых врагов (Zombie, Robot), не меняя код базового класса Enemy. Старый код не ломается, а расширяется.

Почему используется abstract class?

Абстрактный класс Enemy - это как общий шаблон для всех врагов. В нём описано, что у любого врага должна быть атака (метод Attack), но как именно атаковать - решает каждый конкретный враг (Zombie, Robot). Благодаря этому ты можешь создавать новых врагов, просто наследуя этот шаблон, и не трогать уже написанный код. Это и есть суть принципа: расширяем, не изменяя старое.


L - Liskov Substitution Principle

Замена без сюрпризов.

Пример:
Ты арендуешь машину. Какая бы марка ни была - главное, чтобы она ехала и тормозила. Так и в коде: если функция ждёт "животное", можно подставить "кошку" или "собаку", и всё будет работать.

Пример в коде:
// Любой Enemy можно подставить
void DamageEnemy(Enemy enemy) {
    enemy.Attack();
}

Что происходит в коде:
Функция DamageEnemy работает с любым наследником Enemy - не важно, зомби это или робот. Всё будет работать одинаково.


I - Interface Segregation Principle

Лучше несколько маленьких меню, чем одно огромное.

Пример:
В ресторане есть отдельное меню для напитков и отдельное для десертов. Никто не хочет искать среди 50 страниц мороженое.

Пример в коде:
// Маленькие интерфейсы
public interface IShoot {
    void Shoot();
}
public interface IReload {
    void Reload();
}

// Пистолет реализует оба интерфейса
public class Pistol : IShoot, IReload {
    public void Shoot() { /* стреляет */ }
    public void Reload() { /* перезаряжается */ }
}

// Граната реализует только стрельбу
public class Grenade : IShoot {
    public void Shoot() { /* взрывается */ }
    // Нет метода Reload
}

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

Что такое interface?

Interface - это как договор или инструкция, в которой написано, какие методы должны быть у класса. Но сам interface не содержит реализацию - он только говорит: "Если ты реализуешь этот interface, у тебя обязательно должен быть такой-то метод". Например, если класс реализует IShoot, значит, в нём обязательно будет метод Shoot(). Это помогает делать код более гибким и понятным.


D - Dependency Inversion Principle

Зависеть от абстракций, а не от деталей.

Пример:
Ты вызываешь такси через приложение. Тебе всё равно, какая машина приедет - главное, чтобы она довезла до точки Б.

Пример в коде:
// Работаем с абстракцией
public class WeaponUser {
    private IShoot weapon;
    public WeaponUser(IShoot weapon) {
        this.weapon = weapon;
    }
    public void UseWeapon() {
        weapon.Shoot();
    }
}

Что происходит в коде:
Класс WeaponUser работает с любым оружием, которое реализует интерфейс IShoot. Можно легко подменить пистолет на лазер - код не изменится.


Итог

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

А так же рекомендую изучить принципы KISS, DRY, YAGNI и BDUF - они отлично дополняют SOLID!

Теги:
Хабы:
0
Комментарии7

Публикации

Ближайшие события