Ответ
В своей работе я применяю все пять принципов SOLID для создания поддерживаемого и расширяемого кода.
-
Принцип единственной ответственности (Single Responsibility Principle, SRP): Каждый класс должен иметь одну и только одну причину для изменения. Например, я разделяю класс, отвечающий за данные пользователя, и класс, отвечающий за отправку уведомлений.
// Плохо: Класс делает две вещи class UserService { public void saveUser(User user) { /*...*/ } public void sendEmail(User user) { /*...*/ } } // Хорошо: Ответственности разделены class UserRepository { public void save(User user) { /*...*/ } } class NotificationService { public void sendWelcomeEmail(User user) { /*...*/ } } -
Принцип открытости/закрытости (Open/Closed Principle, OCP): Классы должны быть открыты для расширения, но закрыты для модификации. Я достигаю этого через абстракции и полиморфизм.
interface DiscountStrategy { double applyDiscount(double price); } class RegularDiscount implements DiscountStrategy { /*...*/ } class PremiumDiscount implements DiscountStrategy { /*...*/ } class Order { private DiscountStrategy discount; // Добавление новой скидки не требует изменения класса Order } -
Принцип подстановки Барбары Лисков (Liskov Substitution Principle, LSP): Объекты в программе должны быть заменяемыми на экземпляры их подтипов без изменения правильности программы. Наследник не должен ужесточать предусловия или ослаблять постусловия родителя.
// Нарушение LSP: Квадрат не может заменить Прямоугольник, если у того есть сеттеры для ширины и высоты по отдельности. // Соблюдение LSP: Наследование используется только при истинном отношении "is-a". -
Принцип разделения интерфейса (Interface Segregation Principle, ISP): Много специализированных интерфейсов лучше, чем один универсальный. Клиенты не должны зависеть от методов, которые они не используют.
// Вместо одного "толстого" интерфейса: // interface Worker { void work(); void eat(); } // Я создаю раздельные: interface Workable { void work(); } interface Eatable { void eat(); } class Human implements Workable, Eatable { /*...*/ } class Robot implements Workable { /*...*/ } // Robot не зависит от Eatable -
Принцип инверсии зависимостей (Dependency Inversion Principle, DIP): Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций. На практике я внедряю зависимости через конструктор, используя интерфейсы.
interface Database { void save(Data data); } class MySQLDatabase implements Database { /*...*/ } class MongoDB implements Database { /*...*/ } class OrderService { private final Database db; // Зависимость от абстракции public OrderService(Database db) { this.db = db; } public void process(Order order) { db.save(order.getData()); } }
Следование этим принципам помогает мне писать код, который легче тестировать, рефакторить и адаптировать к новым требованиям.
Ответ 18+ 🔞
Э, слушай, вот сидишь ты такой, пишешь код, и вроде всё работает. Но потом приходит коллега, смотрит на твоё творение и говорит: «Чувак, тут терпения ноль ебать, как в этом разбираться?». И ты сам через полгода от своего же кода охуеешь. Чтобы такого не было, есть пять простых, блядь, правил — SOLID. Это не какая-то пиздопроебибна, а реально рабочие штуки.
-
Принцип одной ответственности (SRP). Суть проще пареной репы: один класс — одна работа. Не надо делать из класса манда с ушами, который и данные сохраняет, и письма шлёт, и чай заваривает. Разделяй, блядь.
// Плохо: Класс — тот ещё распиздяй, делает всё подряд. class UserService { public void saveUser(User user) { /*...*/ } public void sendEmail(User user) { /*...*/ } } // Хорошо: Каждый мудак знает свой шесток. class UserRepository { public void save(User user) { /*...*/ } // Только сохранение } class NotificationService { public void sendWelcomeEmail(User user) { /*...*/ } // Только отправка } -
Принцип открытости/закрытости (OCP). Код должен быть как хороший диван: расширяем, но не переделываем. Хочешь добавить новую фичу — не лезь с паяльником в старый код, а расширь его через интерфейсы. Ёпта, красота же.
interface DiscountStrategy { double applyDiscount(double price); } class RegularDiscount implements DiscountStrategy { /*...*/ } class PremiumDiscount implements DiscountStrategy { /*...*/ } class Order { private DiscountStrategy discount; // Хочешь скидку для пидарасов шерстяных? Просто новый класс создай, этот трогать не надо. } -
Принцип подстановки Лисков (LSP). Если уж ты говоришь, что твой класс — потомок другого, то он должен быть ему настоящей заменой. А не как с квадратом и прямоугольником: вроде квадрат — это прямоугольник, а подставить его — и всё, пиздец, логика ломается. Наследование — это вам не хуй с горы, думать надо.
-
Принцип разделения интерфейса (ISP). Не заставляй класс реализовывать то, что ему нахуй не сдалось. Лучше десять маленьких и точных интерфейсов, чем один толстый, от которого всем тошно.
// Вместо этого монстра: // interface Worker { void work(); void eat(); } // Делаем так: interface Workable { void work(); } interface Eatable { void eat(); } class Human implements Workable, Eatable { /*...*/ } // Человек и пашет, и жрёт class Robot implements Workable { /*...*/ } // Роботу похуй на метод eat(), он его не реализует -
Принцип инверсии зависимостей (DIP). Это, блядь, самое важное. Верхнеуровневые модули не должны зависеть от низкоуровневых костылей. Оба должны смотреть в одну сторону — на абстракцию. Пишешь сервис заказов? Он не должен знать про MySQL или MongoDB. Он должен знать про интерфейс
Database. А уж что туда подсунуть — решай потом.interface Database { void save(Data data); } class MySQLDatabase implements Database { /*...*/ } class MongoDB implements Database { /*...*/ } class OrderService { private final Database db; // Вот она, зависимость от абстракции, а не от конкретной хуйни! public OrderService(Database db) { this.db = db; } // Подсунули что надо — и работает public void process(Order order) { db.save(order.getData()); } }
Вот если эти принципы в голове держать, то код из говна и палок не получится. Его и тестировать легче, и изменять, когда менеджер опять с новой хуйнёй прибежит. Сам от себя охуеешь, насколько всё стало проще.