C#

C# 기초부터 고급까지 Chapter 2.1.3. LSP (Liskov Substitution Principle) – 리스코프 치환 원칙

Juan_ 2025. 4. 27. 21:04
728x90

📚 Chapter 2.1.3. LSP (Liskov Substitution Principle) – 리스코프 치환 원칙

✅ LSP란?

"자식 클래스는 부모 클래스를 대체할 수 있어야 한다."
(Subtypes must be substitutable for their base types)
  • 부모 클래스를 사용하는 코드가
  • 자식 클래스로 바꿔 끼웠을 때도
  • 아무 문제 없이 동작해야 한다!

📚 왜 LSP가 중요한가?

문제 상황 결과
자식 클래스가 부모 규칙을 깨뜨림 프로그램이 비정상 동작함
예상치 못한 에러 발생 다형성(polymorphism)이 깨짐
유지보수 지옥 코드 수정할 때 어디 터질지 모름

✅ LSP를 지키면 → 다형성이 제대로 작동하고, 시스템 안정성 쭉 상승!

🛠️ 나쁜 예제: LSP 위반

부모 클래스

public class Bird
{
    public virtual void Fly()
    {
        Console.WriteLine("날아간다!");
    }
}

자식 클래스

public class Ostrich : Bird
{
    public override void Fly()
    {
        throw new NotSupportedException("타조는 못 날아요!");
    }
}

❌ 문제점

  • Bird 타입 쓰는 코드가 "당연히 날겠지" 기대
  • Ostrich는 Fly() 호출 시 예외 발생
  • 부모 계약을 자식이 깨버림 → LSP 위반

🛠️ 좋은 예제: LSP 지킨 버전

1. 설계 수정

public abstract class Bird
{
    public string Name { get; set; }
}

public interface IFlyable
{
    void Fly();
}

2. 역할에 맞게 분리

public class Sparrow : Bird, IFlyable
{
    public void Fly()
    {
        Console.WriteLine($"{Name}가 날고 있다!");
    }
}

public class Ostrich : Bird
{
    // 날지 않는 새는 IFlyable 구현 안 함
}

3. 사용하는 코드

List<IFlyable> flyingBirds = new List<IFlyable>
{
    new Sparrow { Name = "참새" }
};

foreach (var bird in flyingBirds)
{
    bird.Fly();
}

📚 실무 스타일 예시: 결제 처리

부모 클래스 자식 클래스
PaymentMethod CreditCardPayment, PayPalPayment

✨ LSP 심화 – 실전 설계 꿀팁

상황 해결법
override 하면서 예외 던진다 LSP 위반 의심
자식이 부모보다 기능 제한 LSP 위반 가능성
일부 기능이 불가능한 자식 타입 쪼개서 분리 설계

🎯 LSP를 지키면 생기는 실무 장점

항목 효과
안정성 확보 다형성 깨지지 않음
유지보수 쉬움 새 기능 추가해도 기존 코드 무너질 위험 적음
테스트 코드 안정화 부모 타입 테스트 그대로 자식 타입 테스트 가능

✅ LSP 요약

항목 설명
목표 부모 타입을 자식 타입으로 자유롭게 교체 가능해야 함
신호 자식 클래스가 부모 계약 깨거나, 기능 제한하면 위험
해결책 추상 클래스 + 인터페이스 조합으로 역할 분리
728x90