Ответ
Принцип подстановки Лисков (LSP): Объекты базового класса должны быть заменяемы объектами производного класса без изменения корректности программы.
Классическое нарушение в Java: Класс java.util.Stack<E>, который наследуется от java.util.Vector<E>.
Почему это нарушение LSP?
Stack по своей семантике — структура данных LIFO (Last-In-First-Out). Его публичный контракт — операции push, pop, peek. Наследуясь от Vector, он «наследует» множество публичных методов, которые нарушают этот контракт и позволяют модифицировать стек произвольным образом.
import java.util.Stack;
public class LSPViolationExample {
public static void main(String[] args) {
Stack<String> stack = new Stack<>();
stack.push("First"); // Корректная операция стека
stack.push("Second");
// НАРУШЕНИЕ LSP: Методы, унаследованные от Vector,
// ломают инварианты стека (доступ к произвольному элементу).
stack.insertElementAt("Intruder", 0); // Метод из Vector!
stack.remove(1); // Метод из Vector!
// Теперь поведение pop() не соответствует LIFO.
System.out.println(stack.pop()); // Что будет выведено? Неочевидно.
}
}
Следствия нарушения:
- Ненадежность: Клиентский код, использующий
StackкакVector, может сломать логику стека. - Нарушение инкапсуляции: Внутреннее состояние (порядок элементов) можно изменить в обход основных методов.
- Невозможность безопасной замены:
Stackне может быть использован везде, где ожидаетсяVector, без риска ошибок.
Правильная реализация (соответствующая LSP) должна была использовать композицию: хранить Vector или ArrayList как приватное поле и предоставлять только методы стека, делегируя им вызовы к внутренней коллекции.
Ответ 18+ 🔞
Ну вот, опять эти ваши принципы, блядь. Солид, SOLID, как там его... А четвёртая буква — это как раз про Лисков, сука. И звучит она умно: «Объекты базового класса должны быть заменяемы объектами производного класса без изменения корректности программы». Ну, вроде логично, да? Ага, щас.
А теперь смотри сюда, на эту классику жанра, на этот пиздец, который прямо в ядре Java засел, как заноза в жопе. java.util.Stack. Помнишь его? Стек, LIFO, последний зашёл — первый вышел. Всё просто, как три копейки.
Так вот, блядь, создатели Java, видимо, в тот день ебали мозг друг другу, а не думали. Потому что они взяли и наследовали этот Stack от java.util.Vector. Ну, типа, вектор — это список с доступом по индексу, а стек — это типа частный случай, да? Ага, частный случай, который ломает всю логику нахуй!
Смотри, в чём трагедия, блядь. У стека контракт простой: push, pop, peek. Засунул, вынул, посмотрел верхушку. Всё, пиздец. А что он получает от папочки Vector? Овердохуище методов! insertElementAt, remove, get по любому индексу! Это ж как, понимаешь? Тебе дали сейф, а к нему прилагается отмычка на все замки и инструкция, как его взорвать. Ну нахуя?
import java.util.Stack;
public class LSPViolationExample {
public static void main(String[] args) {
Stack<String> stack = new Stack<>();
stack.push("First"); // Нормально, по-человечески
stack.push("Second"); // Тоже ок
// А ТУТ НАЧИНАЕТСЯ ЦИРК, БЛЯДЬ!
// Это методы от Vector, они тут как гандон на свадьбе.
stack.insertElementAt("Intruder", 0); // Засунул хуй знает куда!
stack.remove(1); // Выдрал середину нахуй!
// И теперь попробуй угадай, что вынет pop()?
// Первый? Второй? Интрудера? Хуй его знает! Семантика LIFO накрылась медным тазом.
System.out.println(stack.pop()); // Сюрприз, сука!
}
}
Вот и получается, что Stack — это НЕ Vector. Его нельзя воткнуть туда, где ждут Vector, потому что он начнёт творить дичь. Клиентский код, который работает с Vector, может спокойно вызвать insertElementAt и даже не подозревать, что он только что сломал священный принцип стека. Инкапсуляция? Да её тут и не пахнет, блядь! Внутреннее состояние объекта можно ебашить со всех сторон, как тупую мартышку.
А правильный-то путь какой был, ёпта? Да ебаный рот, композиция! Надо было не наследоваться от Vector, а содержать его внутри, как приватное поле. И уже к этому полю делегировать только те операции, которые нужны стеку. push -> add, pop -> remove(last). И всё, пиздец. Никаких лишних дырок в контракте. Тогда бы Stack был настоящим стеком, а не этим уродцем-полукровкой.
Вот так вот, блядь. Даже в стандартной библиотеке таких граблей наставлено — овердохуища. Учись на чужих косяках, а то сам такого наворотишь, потом будешь глазами хлопать, как Герасим, и мычать «Му-му», блядь.