Liskov Substitution Principle is the principle that when we extend a class, we must ensure the correctness of that class.
An example that you often see when learning about this principle is that a rectangle must be a rectangle, the width and length must always be different:
1 2 3 4 5 6 7 8 9 10 11 |
package com.huongdankotlin.designpattern.lsp open class Rectangle { open var width: Int = 0 open var height: Int = 0 fun area(): Int { return this.width * this.height; } } |
You should not extend the class that defines a rectangle to build a square class and then define the two sides of the square to be equal:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package com.huongdankotlin.designpattern.lsp class Square : Rectangle() { override var width: Int get() = super.width set(value) { super.width = value super.height = value } override var height: Int get() = super.height set(value) { super.height = value super.width = value } } |
So that when we instantiate 2 Rectangle objects with 2 different implementations, the results when calculating the area are different, even though they are both rectangles and have the same length and width:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package com.huongdankotlin.designpattern.lsp fun main() { var r1 = Rectangle() r1.width = 5 r1.height = 4 println(r1.area()) var r2: Rectangle = Square() r2.width = 5 r2.height = 4 println(r2.area()) } |
Result:
To solve the problem in this case, you should introduce a Shape interface with an abstract method area():
1 2 3 4 5 |
package com.huongdankotlin.designpattern.lsp interface Shape { fun area(): Int } |
The two classes Rectangle and Square will now implement the Shape interface:
1 2 3 4 5 6 7 8 9 10 11 |
package com.huongdankotlin.designpattern.lsp open class Rectangle: Shape { var width: Int = 0 var height: Int = 0 override fun area(): Int { return this.width * this.height; } } |
and:
1 2 3 4 5 6 7 8 9 |
package com.huongdankotlin.designpattern.lsp class Square : Shape { var side: Int = 0 override fun area(): Int { return side * side; } } |
And when calculating the area of the two shapes above:
1 2 3 4 5 6 7 8 9 10 11 12 |
package com.huongdankotlin.designpattern.lsp fun main() { var r1: Rectangle = Rectangle() r1.width = 5 r1.height = 4 println(r1.area()) var r2: Square = Square() r2.side = 5 println(r2.area()) } |
the result will always be correct: