Ответ
Принцип открытости/закрытости (Open/Closed Principle, OCP): Программные сущности (классы, модули, функции) должны быть открыты для расширения, но закрыты для модификации.
- Закрыты для модификации: Существующий, протестированный код не должен изменяться при добавлении новой функциональности.
- Открыты для расширения: Новая функциональность добавляется путём создания нового кода (наследование, композиция, реализация интерфейсов).
Пример нарушения OCP:
class AreaCalculator {
public double calculateArea(Object shape) {
if (shape instanceof Circle) {
Circle c = (Circle) shape;
return Math.PI * c.radius * c.radius;
} else if (shape instanceof Rectangle) {
Rectangle r = (Rectangle) shape;
return r.width * r.height;
}
// Добавление новой фигуры (Triangle) требует изменения этого метода!
throw new IllegalArgumentException("Unknown shape");
}
}
Пример соблюдения OCP:
// 1. Абстракция, открытая для расширения
interface Shape {
double area();
}
// 2. Конкретные реализации. Их код закрыт для модификации.
class Circle implements Shape {
private double radius;
public Circle(double radius) { this.radius = radius; }
@Override
public double area() { return Math.PI * radius * radius; }
}
class Rectangle implements Shape {
private double width, height;
public Rectangle(double w, double h) { width = w; height = h; }
@Override
public double area() { return width * height; }
}
// 3. Класс-клиент. Его код также закрыт для модификации.
class AreaCalculator {
public double calculateTotalArea(List<Shape> shapes) {
return shapes.stream().mapToDouble(Shape::area).sum();
}
}
Как добавить новую фигуру Triangle?
- Создаём новый класс
Triangle implements Shapeс реализациейarea(). - Никаких изменений в классах
Circle,RectangleилиAreaCalculatorне требуется.
Выгода: Система становится устойчивой к изменениям, снижается риск внесения ошибок в существующий код.
Ответ 18+ 🔞
Да ты посмотри, что за пиздопроебибна творится в этом коде! Сидит себе программист, как Герасим, под лестницей, и думает: "Му-му, всё норм". А потом бац — нужно треугольник добавить. И что он делает? Правильно, лезет в свой проверенный метод calculateArea и начинает там хуячить if (shape instanceof Triangle).
Вот это и есть, блядь, нарушение принципа открытости-закрытости в чистом виде! Сущность должна быть, как жена друга — закрыта для модификации, но открыта для расширения, ёпта! То есть ты не должен лезть в старый, рабочий код с криками "я ща всё починю!". Ты должен нахуй создать новую сущность и через неё всё сделать.
Смотри, вот пример, от которого волосы дыбом встают:
class AreaCalculator {
public double calculateArea(Object shape) {
if (shape instanceof Circle) {
Circle c = (Circle) shape;
return Math.PI * c.radius * c.radius;
} else if (shape instanceof Rectangle) {
Rectangle r = (Rectangle) shape;
return r.width * r.height;
}
// А тут, сука, когда треугольник понадобится, придётся этот метод пилить!
throw new IllegalArgumentException("Unknown shape");
}
}
Представляешь? Каждый раз, когда новая фигура появляется, ты будешь этот метод допиливать. Это ж пиздец, чувак! Один раз напишешь, а потом всю жизнь его ебашить. Терпения ноль ебать!
А теперь смотри, как умные люди делают. Сначала они создают интерфейс — этакую абстрактную херовину, которая говорит: "Ребята, если хотите со мной работать, реализуйте метод area()". И всем похуй, как ты его реализуешь.
interface Shape {
double area();
}
А дальше — красота! Каждая фигура живёт своей жизнью, как в коммуналке. Круг знает про круги, прямоугольник — про прямоугольники. И никто никому в тарелку не плюёт.
class Circle implements Shape {
private double radius;
public Circle(double radius) { this.radius = radius; }
@Override
public double area() { return Math.PI * radius * radius; } // Считает по-своему
}
class Rectangle implements Shape {
private double width, height;
public Rectangle(double w, double h) { width = w; height = h; }
@Override
public double area() { return width * height; } // Считает по-своему
}
И главный калькулятор теперь — просто царь! Он нихуя не знает про конкретные фигуры. Его дело — брать список этих Shape и вызывать у каждого area(). Он закрыт, как швейцарский банк, блядь!
class AreaCalculator {
public double calculateTotalArea(List<Shape> shapes) {
return shapes.stream().mapToDouble(Shape::area).sum(); // И всё! Красота!
}
}
И вот, наступает момент истины. Нам срочно понадобился треугольник. Раньше бы мы, сука, побежали в AreaCalculator и начали там всё ломать. А сейчас? Сейчас мы просто создаём новый класс:
class Triangle implements Shape {
private double base, height;
public Triangle(double b, double h) { base = b; height = h; }
@Override
public double area() { return 0.5 * base * height; } // Формулу из школы вспомнил!
}
И ВСЁ! Ни один существующий класс — ни Circle, ни Rectangle, ни сам AreaCalculator — даже не узнают, что треугольник появился. Они как жили в своём уютном мире, так и живут. AreaCalculator возьмёт этот треугольник в список и спокойно вызовет у него area(), потому что тот обещал этот метод реализовать.
Вот это и есть принцип, блядь! Система становится устойчивой, как танк. Риск накосячить в старом коде — ноль ебать. Добавляй хоть трапецию, хоть эллипс, хоть манда с ушами, если она реализует интерфейс Shape — всё будет работать.
Вот так-то, а не через жопу instanceof проверки пихать. Чих-пых тебя в сраку, учи матчасть!