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 준수, 즉 추상화/다형성 기반의 올바른 설계를 위한 주요 원칙을 제시