Search
Duplicate
🏓

LSP : The Liskov Substitution Principle

Category
S/W 엔지니어
Tags
SOLID
Architecture
S/W Engineering
Study Note
LSP
Created time
2009/04/15

Definition

상속 시 부모와 자식의 관계가 반드시 IS-A 관계를 유지하도록, 좀더 정확히 하자면, 부모를 치환(substitution) 가능한 자식을 만들도록.
상속 관계 코드 작성 시의 원칙. Base type의 사용 조건을 derived type에서 모두 따를 수 있도록

LSP violated sample

public class Line { public Line(Point p1, Point p2){ /*code*/} } public Point P1 { get { /*code*/} } } public Point P2 { get { /*code*/} } } public virtual bool IsOn(Point p) {/*code*/} } public class LineSegment : Line { public LineSegment(Point p1, Point p2) : base(p1, p2) {} public double Length() { get {/*code*/} } //Line.IsOn()의 참이 아래에서는 거짓이 될 수 있음. public override bool IsOn(Point p) {/*code*/} } class LineClient { void DoSomething(Line) { /*code*/ } }
C#
복사
LineClient.DoSomething()은 해당 매개변수(line) 위의 모든 점에서 IsOn() == true를 기대하고 코드 작성 가능.
하지만 선분인 LineSegment instance를 LineClient.DoSomething()의 매개변수로 넘길 경우, IsOn() == false가 가능함으로 LineClient.DoSomething()은 유효하지 않은 코드가 됨.
Base class client 코드는 일반적으로 derived class에 대한 지식을 고려하지 않고(base class에 대한 지식만으로) client 코드를 작성. 하지만 해당 client code로 derived class의 instance가 전달될 수 있으며, 이 때 LSP 위반 시 해당 operation은 무효화 됨. 즉, 잠재적 버그 유발 가능.

LSP 준수 방법

1.
DBC(Design by Contract; 계약에 의한 설계)
Overriding 시, base class에서의 pre condition과 같거나 더 약한 수준에서 동작하고, post condition에서는 같거나 더 강한 수준에서 동작하도록 설계하여야(Base class의 모든 명시적/암시적 계약을 만족한 derived class 작성).
2.
deriving 대신 factoring(공통 인자 추출)
public abstract class LinearObject { public LinearObject(Point p1, Point p2) { /*code*/} } public Point P1 { get { /*code*/} } } public Point P2 { get { /*code*/} } } public abstract virtual bool IsOn(Point p); } public class Line : LinearObject { public Line(Point p1, Point p2) : base(p1, p2) {} public override bool IsOn(Point p) {/*code*/} } public class LineSegment : LinearObject { public LineSegment(Point p1, Point p2) : base(p1, p2) {} public double GetLength() {/*code*/} public override bool IsOn(Point p) {/*code*/} } class LineClient { void DoSomething(Line) { /*code*/ } }
C#
복사
Line과 LineSegment의 공통적 특성을 추출하여 공통 상위 클래스(LinearObject) 생성
LineClient.DoSomething()은 더 이상 잠재적 버그를 갖지 않음
일반적으로 factoring을 통한 공통의 상위 클래스는 abstract가 될 가능성이 높고, 해당 상위 클래스는 언젠가 그 자체만의 client code를 갖기 마련.

Conclusion

LSP 위반은 base class 만 알던 client code의 변경을 유발하므로(derived class에 대한 고려가 필요하기 때문에), OCP 위반이란 부정적 파급 현상을 야기함.
OCP 준수, 즉 추상화/다형성 기반의 올바른 설계를 위한 주요 원칙을 제시