본문 바로가기
컴퓨터 과학/소프트웨어공학

[소프트웨어공학] SOLID(3) : 리스코프 치환 원칙(Liskov Substitution Principle, LSP)

by webcodur 2024. 3. 29.
728x90
반응형

 

목차

    리스코프 치환 원칙(Liskov Substitution Principle, LSP)

    SOLID 원칙 중 L은 Liskov 치환 원칙(Liskov Substitution Principle, LSP)을 의미한다. 이 원칙은 하위 타입은 항상 그들의 기반 타입으로 대체될 수 있어야 한다고 말한다. 즉, 클래스의 인스턴스를 해당 클래스의 부모 타입의 인스턴스로 대체해도 프로그램의 정확성에 영향을 미치지 않아야 한다는 것이다. 이 원칙을 지키면 코드의 재사용성과 유지보수성이 높아진다.

    LSP를 지키지 않은 코드 예제와 이를 수정하여 LSP를 지키는 코드 예제를 게임을 주제로 작성해 보겠다.

     

    LSP를 지키지 않은 코드 예제

    이 예제에서는 게임 캐릭터와 이를 상속받는 특수 캐릭터 클래스를 다룬다. 특수 캐릭터는 일반 캐릭터와 다른 동작을 수행하는데, LSP를 지키지 않게 되면 상속 받은 메소드가 기대하는 동작을 하지 않게 될 수 있다.

    using System;
    
    public class GameCharacter {
        public virtual void Attack() {
            Console.WriteLine("기본 공격을 한다.");
        }
    }
    
    public class SpecialCharacter : GameCharacter {
        public override void Attack() {
            throw new NotImplementedException("특수 캐릭터는 기본 공격을 사용할 수 없다.");
        }
    
        public void SpecialAttack() {
            Console.WriteLine("특수 공격을 한다.");
        }
    }
    
    public class Program {
        static void Main(string[] args) {
            GameCharacter character = new SpecialCharacter();
            character.Attack(); // 런타임 에러 발생
        }
    }
    

     

    이 코드에서 SpecialCharacterGameCharacterAttack 메소드를 오버라이드하여 구현한다. 그러나 Attack 메소드에서 NotImplementedException 을 발생시켜, GameCharacter의 인스턴스 대신 SpecialCharacter 의 인스턴스를 사용할 때 기대한 동작을 하지 않게 된다.

     

    LSP를 지키는 코드 예제

    LSP 원칙을 준수하기 위해서는 모든 하위 클래스가 상위 클래스의 행동을 적절히 구현해야 한다. 이를 위해 인터페이스를 사용하여 각 캐릭터의 공격 방식을 명시적으로 구분할 수 있다.

    using System;
    
    public interface ICharacter {
        void Attack();
    }
    
    public class GameCharacter : ICharacter {
        public void Attack() {
            Console.WriteLine("기본 공격을 한다.");
        }
    }
    
    public class SpecialCharacter : ICharacter {
        public void Attack() {
            SpecialAttack();
        }
    
        private void SpecialAttack() {
            Console.WriteLine("특수 공격을 한다.");
        }
    }
    
    public class Program {
        static void Main(string[] args) {
            ICharacter character = new SpecialCharacter();
            character.Attack(); // "특수 공격을 한다." 정상 출력
        }
    }
    
    

     

    이 코드는 GameCharacterSpecialCharacter가 모두 ICharacter 인터페이스를 구현하도록 변경하여, Attack 메소드가 모든 캐릭터 타입에 대해 의미 있는 구현을 가지도록 만든다. 이로써 LSP 원칙을 준수하며, 각 캐릭터 타입이 Attack 메소드를 자신만의 방식으로 구현할 수 있게 된다.

    반응형