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 ์ค€์ˆ˜, ์ฆ‰ ์ถ”์ƒํ™”/๋‹คํ˜•์„ฑ ๊ธฐ๋ฐ˜์˜ ์˜ฌ๋ฐ”๋ฅธ ์„ค๊ณ„๋ฅผ ์œ„ํ•œ ์ฃผ์š” ์›์น™์„ ์ œ์‹œ

Comments