Если ты только начал программировать на 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!
ссылка на оригинал статьи https://habr.com/ru/articles/940620/
Добавить комментарий