Урок 12. SOLID
Принципы SOLID — это набор пяти принципов объектно-ориентированного программирования, которые помогают разработчикам создавать более гибкие, поддерживаемые и масштабируемые системы. Эти принципы были предложены Робертом Мартином (Robert C. Martin) и являются основой для хорошего проектирования программного обеспечения. Давайте рассмотрим каждый из принципов подробнее.
1. S - Single Responsibility Principle (SRP)
Принцип: Принцип единственной ответственности утверждает, что у класса должна быть только одна причина для изменения. Это означает, что класс должен иметь только одну ответственность или задачу.
Пример:
public class Report {
public void generateReport() {
// Логика генерации отчета
}
}
public class ReportPrinter {
public void printReport(Report report) {
// Логика печати отчета
}
}
В этом примере класс Report
отвечает только за генерацию отчета, а класс ReportPrinter
— за его печать. Это упрощает поддержку и тестирование.
2. O - Open/Closed Principle (OCP)
Принцип: Принцип открытости/закрытости утверждает, что классы должны быть открыты для расширения, но закрыты для модификации. Это означает, что вы должны иметь возможность добавлять новую функциональность, не изменяя существующий код.
Пример:
public abstract class Shape {
public abstract double area();
}
public class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
public class Rectangle extends Shape {
private double width;
private double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public double area() {
return width * height;
}
}
В этом примере вы можете добавлять новые фигуры, создавая новые классы, не изменяя существующий код.
3. L - Liskov Substitution Principle (LSP)
Принцип: Принцип подстановки Лисков утверждает, что объекты подкласса должны быть взаимозаменяемыми с объектами суперкласса. Это означает, что если класс S является подклассом класса T, то объекты типа T должны быть заменяемы объектами типа S без изменения правильности программы.
Пример:
public class Bird {
public void fly() {
System.out.println("Flying");
}
}
public class Sparrow extends Bird {
@Override
public void fly() {
System.out.println("Sparrow flying");
}
}
public class Ostrich extends Bird {
@Override
public void fly() {
throw new UnsupportedOperationException("Ostriches can't fly");
}
}
В этом примере класс Ostrich
нарушает принцип LSP, так как не может заменить Bird
без изменения поведения программы. Лучше использовать интерфейсы или абстрактные классы для разделения поведения.
4. I - Interface Segregation Principle (ISP)
Принцип: Принцип разделения интерфейсов утверждает, что клиенты не должны зависеть от интерфейсов, которые они не используют. Это означает, что лучше создавать узкоспециализированные интерфейсы, чем один общий интерфейс.
Пример:
public interface Printer {
void print();
}
public interface Scanner {
void scan();
}
public class MultiFunctionPrinter implements Printer, Scanner {
@Override
public void print() {
System.out.println("Printing");
}
@Override
public void scan() {
System.out.println("Scanning");
}
}
В этом примере интерфейсы Printer
и Scanner
разделены, что позволяет создавать классы, которые реализуют только необходимые функции.
5. D - Dependency Inversion Principle (DIP)
Принцип: Принцип инверсии зависимостей утверждает, что высокоуровневые модули не должны зависеть от низкоуровневых модулей. Оба типа модулей должны зависеть от абстракций (например, интерфейсов). Это помогает уменьшить связанность между компонентами.
Пример:
```java public interface MessageService { void sendMessage(String message); }
public class EmailService implements MessageService { @Override public void sendMessage(String message) { System.out.println("Sending email: " + message); } }
public class Notification { private MessageService messageService;