〰️
Programming with Java
  • Програмиране с JAVA
  • Обектно-ориентирано програмиране - 1 част
    • Лабораторно упражнение 1
      • Основи на програмирането с Java за начинаещи‎
        • Oбщи термини в Java
        • Основни характеристики на JAVA‎
        • Инсталиране на JDK
        • Инсталиране на Intellij
      • Първа програма в Java
      • Системен изход в JAVA
      • Дефиниране на променливи
      • Примитивни типове данни
      • Оператори
      • If-else
      • Switch-Case
      • For loop
      • While loop
      • Do-while loop
      • Continue
      • Break
      • Задачи
    • Лабораторно упражнение 2
      • Клас
      • Обект
      • Ключова дума new
      • Запазена дума static
      • Конвенции за именуване в Java
      • Wrapper Class
      • Сравняване на
      • Нуждата Wrapper Class
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 3
      • Наследяване
      • this и super
      • Модификатори за достъп
      • Капсулиране
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 4
      • Проследяване на грешки
      • Оценяване на изрази
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 5
      • Полиморфизъм
      • Абстрактен клас
      • Интерфейс
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 6
      • Разлика между Абстрактен клас и Интерфейс
        • Разлика 1
        • Разлика 2
        • Разлика 3
        • Разлика 4
        • Разлика 5
        • Разлика 6
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 7
      • String
      • Enum
      • Обработка на изключения
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 8
      • Генерични класове
      • Генеричен метод
      • Параметри на типа в Java Generics
      • Предимства на генериците
      • Генериците работят само с референтни типове
    • Лабораторно упражнение 9
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 10
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 11
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 12
      • Упражнения за извънаудиторна заетост
    • Лабораторно упражнение 13
      • Упражнения за извънаудиторна заетост
      • Упражнения за извънаудиторна заетост
  • Обектно-ориентирано програмиране - 2 част
    • Лабораторно упражнение 1
      • SRP - Single Responsibility Principle
        • Задачи
      • OCP - Open-Closed Principle
        • Задачи
    • Лабораторно упражнение 2
      • LSP - Liskov Substitution Principle
        • Задачи
      • ISP - Interface Segregation Principle
        • Задачи
      • DI - Dependency Inversion Principle
        • Задачи
    • Лабораторно упражнение 3
      • Singleton
        • Задачи
      • Builder
        • Задачи
    • Лабораторно упражнение 4
      • Factory Method
      • Abstract Factory
      • Задачи
    • Лабораторно упражнение 5
    • Лабораторно упражнение 6
      • Decorator
      • Bridge
        • Композиция
      • Задачи
    • Лабораторно упражнение 7
      • Adapter
      • Задачи
    • Лабораторно упражнение 8
      • Composite
      • Proxy
      • Задачи
    • Лабораторно упражнение 9
    • Лабораторно упражнение 10
      • Visitor
      • State
      • Задачи
    • Лабораторно упражнение 11
      • Observer
      • Задачи
    • Лабораторно упражнение 12
      • Chain of Responsibility
      • Command
      • Задачи
    • Лабораторно упражнение 13
  • Интернет технологии 2023
    • Лабораторно упражнение 1
      • HTTP протокол
        • Синтаксис на URL
        • HTTP съобщения
        • Методи за HTTP заявка
        • Кодове за състояние на HTTP отговор
      • Postman
        • Изпращане на заявка с Postman
        • Получаване на отговор
      • Задачи за работа с Postman
    • Лабораторно упражнение 2
      • Работа с Tomcat
      • Maven
      • Създаване на Maven проект в IntelliJ Ultimate Edition
      • Създаване на Maven проект в IntelliJ Community Edition
      • Създаване на Maven проект в Eclipse IDE
    • Лабораторно упражнение 3
      • Java Servlets
      • Жизнен цикъл на сървлета
      • Създаване на сървлети
      • Задачи за създаване на сървлети
    • Лабораторно упражнение 4
      • Extensible Markup Language
      • Java Architecture for XML Binding
      • JavaScript Object Notation
      • Задачи
    • Лабораторно упражнение 5
    • Лабораторно упражнение 6
      • Spring Boot
      • Създаване на Spring boot проект
      • Структура на Spring Boot проект
        • Файлът pom.xml
        • Main клас в Spring Boot
        • Управление на конфигурацията с application.properties
      • Задача
    • Лабораторно упражнение 7
      • Комуникационен поток и CRUD операции
      • ResponseEntity
      • Избрани анотации
      • Задача
    • Лабораторно упражнение 8
      • Lombok
      • Data transfer object (DTO)
      • Обработване на изключения в Spring Boot приложение
        • Клас Optional<T>
      • Валидиране на данните от заявката
      • Задачи
    • Лабораторно упражнение 9-10
      • Конфигуриране на PostgreSQL DB
      • Jakarta Persistence анотации
      • Repository слой
      • Задачи
    • Лабораторно упражнение 11
      • Проследяване на сесии
      • Филтри и FilterChain
      • Spring Security
        • Добавяне на Spring Security в Spring Boot приложение
        • Конфигуриране на филтри
        • Удостоверяване със Spring Security
        • Защита на метод със Spring Security
      • Задача
    • Лабораторно упражнение 12
      • JSON Web Token
      • Защита с помощта на JWT
      • Задача
    • Лабораторно упражнение 13
  • Програмиране за мобилни и Интернет устройства
    • Лабораторно упражнение 1
      • Задачи
    • Лабораторно упражнение 2
      • Среда за разработване
        • Създаване на проект
        • Структора на проект
        • Виртуално устройство с Android OS
      • Задача
    • Лабораторно упражнение 3
      • Activity
      • Layout
        • XML описание
      • Задача
    • Лабораторно упражнение 4
      • Activity Lifecycle
      • Intent
      • Слушатели на събитията и методи за обратно извикване
      • Задача
    • Лабораторно упражнение 5
      • Слушатели на събитията и методи за обратно извикване
      • Задача
    • Лабораторно упражнение 6
      • Фрагменти
      • DialogFragment
      • Задача
    • Лабораторно упражнение 7
      • Примери
        • BaseAdapter
        • ArrayAdapter
        • Custom ArrayAdapter
      • RecyclerView
        • Пример
      • CardView
      • Задача
    • Лабораторно упражнение 8
      • Runnable
      • HandlerThread
      • ThreadPoolExecutor
      • Задача
    • Лабораторно упражнение 9
      • Задача
      • Задача
      • Пример
  • Интернет Технологии
    • Лабораторно упражнение 1
      • Инсталиране и настройка на необходимата среда за работа в упражненията
      • Maven
      • Създаване на Maven проект в Eclipse IDE
      • Създаване на Maven проект в IntelliJ
      • Работа с Tomcat
      • Задача
    • Лабораторно упражнение 2
      • HTML форми
      • Cascading Style Sheets (CSS)
        • CSS селектори
        • Някои CSS свойства
      • Задача
    • Лабораторно упражнение 3
      • Java Servlets
      • Жизнен цикъл на сървлета
      • Създаване на сървлети
      • Задачи
    • Лабораторно упражнение 4
      • Java Server Pages технология. Същност и детайли
      • Пренасочване между Servlet и JSP
      • Задачи
    • Лабораторно упражение 5
      • Build pattern
      • JavaBean
      • Задачи
    • Лабораторно упражение 6
      • Проследяване на сесии
      • Управление на бисквитки (Cookies)
      • Задачи
    • Лабораторно упражнение 7
      • Проследяване на сесии
      • Управление на бисквитки (Cookies)
      • Servlet Filter
      • Задачи
    • Лабораторно упражнение 8
      • Servlet Filter
      • Прихващане на грешки
      • Задачи
    • Лабораторно упражнение 9
      • Extensible Markup Language
      • JavaScript Object Notation
        • Fetch
      • Задача
    • Лабораторно упражнение 10
      • Java Architecture for XML Binding
      • Задачи
Powered by GitBook
On this page

Was this helpful?

  1. Обектно-ориентирано програмиране - 2 част
  2. Лабораторно упражнение 2

LSP - Liskov Substitution Principle

Барбара Лисков, дефинира принципа през 1988 г., като:

Ако за всеки обект o1 от тип S има обект o2 от тип T такъв, че за всички програми P, дефинирани по отношение на T, поведението на P е непроменено, когато o1 е заместен за o2 тогава S е подтип на T.

Или както го обобщава Робърт С. Мартин:

Подтиповете трябва да бъдат заместващи на базовите си типове.

По отношение на LSP методите, които използват извиккване на базови класове, трябва да могат да използват обекти от производния клас, без да го знаят. С прости думи производните класове трябва да бъдат заместващи на базовия клас, за да е приложен принципа на LSP.

Нека вземем пример за правоъгълници и квадратчета. Има тенденция да се установи връзката, по този начин, можете да кажете, че квадрат е правоъгълник. Възниква обаче проблем (оттук — нарушение на LSP), което се доказва със следния пример.

public class Rectangle {
    private int length;
    private int breadth;
    
    public int getLength() {
        return length;
    }
    public void setLength(int length) {
        this.length = length;
    }
    public int getBreadth() {
        return breadth;
    }
    public void setBreadth(int breadth) {
        this.breadth = breadth;
    }
    public int getArea() {
        return this.length * this.breadth;
    }
}
public class Square extends Rectangle {
    @Override
    public void setBreadth(int breadth) {
        super.setBreadth(breadth);
        super.setLength(breadth);
    }
    @Override
    public void setLength(int length) {
        super.setLength(length);
        super.setBreadth(length);
    }
}
public class LSPDemo {
    public void calculateArea(Rectangle r) {
        r.setBreadth(2);
        r.setLength(3);

        r.getArea() == 6 : printError("area", r);

        r.getLength() == 3 : printError("length", r);
        r.getBreadth() == 2 : printError("breadth", r);
    }

    private String printError(String errorIdentifer, Rectangle r) {
        return "Unexpected value of " + errorIdentifer + "  for instance of " + r.getClass().getName();
    }

    public static void main(String[] args) {
        LSPDemo lsp = new LSPDemo();
        //
        // An instance of Rectangle is passed
        //
        lsp.calculateArea(new Rectangle());
        //
        // An instance of Square is passed
        //
        lsp.calculateArea(new Square());
    }
}

Кодът на метода за пресмятане има Правоъгълник като аргумент. Що се отнася до принципа, функциите, които използват препратки към базовите класове, трябва да могат да използват обекти от производен клас, без да го знаят. По този начин, в примера, метода calculateArea, който използва препратката на "Правоъгълник," трябва да бъде в състояние да използва обектите от производен клас, като Square, и да изпълни изискването, породено от Правоъгълник определение.

Погледнете calculateArea методa за който трябва да отбележи, че според определението за Правоъгълник, следното трябва винаги да бъде вярно:

  • Двете дължини трябва да са винаги равни, setLength.

  • Двете ширини трябва да са винаги равни, setBreadth.

  • Площта трябва винаги да е равна на произведението от дължина и ширина.

В този случай се опитваме да установим връзка между Square и Rectangle такава, че да наричаме "Square е Rectangle" кода би започнал да се държи непредвидено, ако се подаде екземпляр на Square. Грешка в твърдението ще бъде хвърлена в случай на проверка за "Площ" и проверка за "Ширина", въпреки че програмата ще прекрати, тъй като грешката в твърдението е хвърлена поради неуспеха на проверката на Площа.

Като се има предвид примера, какъв е проблемът с отношенията Квадрат-Правоъгълник?

  • Класът Square не се нуждае от методи като setBreadth или setLength, тъй като страните на квадрат са равни. Представете си за стотици хиляди обекти, Square че трябва да се сетват две повтарящи се стойности вместо една.

  • Класът LSPDemo ще трябва да знае подробностите за производните класове Rectangle (като Square), за да изпълнява по подходящ начин, и да се избегне грешка. Ще има нужда от промяната в съществуващия код, за да се грижи за производния клас, на първо място нарушава принципа на еденичната отговорност.

Трябва да се следват някои от характеристиките за качество на кода, които са представени от принципа на Лисков.

  • Само когато производните типове са напълно заместващи за базовите си типове, функциите, които използват тези базови типове, могат да се използват повторно безнаказано, а производните типове могат да бъдат променяни безнаказано.

  • Използвайки този принцип, методите на класовете декларират предварителни условия и постустановени условия. Предварителните условия трябва да са верни, за да може методът да се изпълни. След завършване методът гарантира, че след условието ще бъде вярно.

  • Пройзводните класове трябва да хвърлят изключения за свойствата който не могат да обработят от базовите класове

Правила

  • Правило за подпис относно видове аргументи за метод - Това правило гласи, че типовете аргументи за метода на надместен подтип могат да бъдат идентични или по-широки от типовете аргументи за метода на супертипа.

  • Правило за подпис относно видове типове за връщане - Типът на връщане на метода на замествания метод може да бъде по-конкретен от типа на връщане на метода на супертипа.

  • Правило за свойствата при класовете наследници. Клас наследник трябва да се погрижи да дефинира условие относно свойствата на обекта, които трябва да са верни за всички валидни състояния на обекта.

  • Правило за свойствата ограничение в историята - методите на подкласа не трябва да позволяват промени в състоянието, които базовият клас не е позволил.

  • Правило за методите за предварителни условия - Предварително условие (валидация на данните) трябва да бъде удовлетворено, преди да може да бъде изпълнен метод.

  • Правило за методи следусловия - условие което трябва да бъде изпълнено след изпълнение на метод.

Нека да разгледаме пример:

PreviousЛабораторно упражнение 2NextЗадачи

Last updated 3 years ago

Was this helpful?