ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Liskov Substitution Principle (LSP)
    Modeling/DesignPattern 2020. 2. 28. 00:51

    1. Overview

    We should be to substitute base class objects with child class objects and this should not alter behavior/characteristics of the program.

    2. Description

    For example, Java what we are also talking about behavioral subtypes. That means if the base class object was providing a specific behavior and if that base class object is now substituted with a child class object that behavior should not alter. So what is expected to happen in that particular code should happen even if we change the base class object with the child class object.

    3. Example

    3.1 Violate LSP

    class Rectangle {
        private int width;
        private int height;
        public Rectangle(int width, int height) {
            this.width = width;
            this.height = height;
        }
        public int getWidth() {
            return width;
        }
        public int getHeight() {
            return height;
        }
        public void setWidth(int width) {
            this.width = width;
        }
        public void setHeight(int height) {
            this.height = height;
        }
        public int computeArea() {
            return width * height;
        }
    }
    
    class Square extends Rectangle {
        public Square(int side) {
            super(side, side);
        }
        // This is how we will implement a square That is a rectangle.
        // Mathematically it makes sense that Square is a rectangle.
        // When it comes to object oriented programming that 
        // relationship is not really valid because it violates
        // our contract of setHeight and setWidth method of rectangle class.
        @Override
        public void setWidth(int width) {
            setSide(width);
        }
        @Override
        public void setHeight(int height) {
            setSide(height);
        }
        public void setSide(int side) {
            super.setWidth(side);
            super.setHeight(side);
        }
    }
    
    public class demo {
        public static void main(String[] args) {
            Rectangle rectangle = new Rectangle(10, 20);
            System.out.println(rectangle.computeArea());
    
            Square square = new Square(10);
            System.out.println(square.computeArea());
            useRectangle(rectangle);
            useRectangle(square);
        }
        private static void useRectangle(Rectangle rectangle) {
            // This method occurs failure when it comes to square because we overwrite setHeight and setWidth
            rectangle.setHeight(20);
            rectangle.setWidth(30);
            assert rectangle.getHeight() == 20 : "Height not equal to 20";
            assert rectangle.getWidth() == 30 : "Width not equal to 30";
        }
    }

    3.2 Follow LSP

    interface Shape {
    //    when we are now making sure that anyone who is using our square is not under impression that
    //    he is using a special type of rectangle he's going to know that only thing that is guaranteed by square
    //    is that it will have a compute area method.
        public int computeArea();
    }
    class Rectangle implements Shape{
        private int width;
        private int height;
        public Rectangle(int width, int height) {
            this.width = width;
            this.height = height;
        }
        public int getWidth() {
            return width;
        }
        public int getHeight() {
            return height;
        }
        public void setWidth(int width) {
            this.width = width;
        }
        public void setHeight(int height) {
            this.height = height;
        }
        public int computeArea() {
            return width * height;
        }
    }
    class Square implements Shape {
    
        private int side;
    
        public Square(int side) {
            this.side = side;
        }
        public int getSide() {
            return side;
        }
        public void setSide(int side) {
            this.side = side;
        }
        @Override
        public int computeArea() {
            return side*side;
        }
    }
    
    public class demo {
        public static void main(String[] args) {
            Rectangle rectangle = new Rectangle(10, 20);
            System.out.println(rectangle.computeArea());
    
            Square square = new Square(10);
            System.out.println(square.computeArea());
            useRectangle(rectangle);
    //        now we can use useRectangle because square is not rectangle anymore.
    //        this is how we can avoid violating the list goal substitution principle.
    //        useRectangle(square);
        }
        private static void useRectangle(Rectangle rectangle) {
            // This method occurs failure when it comes to square because we overwrite setHeight and setWidth
            rectangle.setHeight(20);
            rectangle.setWidth(30);
            assert rectangle.getHeight() == 20 : "Height not equal to 20";
            assert rectangle.getWidth() == 30 : "Width not equal to 30";
        }
    }

    4. Reference

    https://en.wikipedia.org/wiki/Liskov_substitution_principle

    'Modeling > DesignPattern' 카테고리의 다른 글

    Dependency Inversion Principle (DIP)  (0) 2020.02.28
    Interface Segregation Principle (ISP)  (0) 2020.02.28
    Open-Closed Principle (OCP)  (0) 2020.02.26
    Single Responsibility Principle (SRP)  (0) 2020.02.26
    State  (0) 2020.02.26

    댓글

Designed by Tistory.