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

[소프트웨어공학] SOLID(4) : 인터페이스 분리 원칙(Interface Segregation Principle, ISP)

by webcodur 2024. 3. 29.
728x90

목차

    인터페이스 분리 원칙(Interface Segregation Principle, ISP)

    SOLID 원칙 중 'I'는 인터페이스 분리 원칙(Interface Segregation Principle, ISP)을 의미한다. 이 원칙은 "클라이언트는 자신이 이용하지 않는 메서드에 의존하면 안 된다"는 개념을 담고 있다. 즉, 한 클래스가 자신이 사용하지 않는 인터페이스를 구현하도록 강제되어서는 안 된다는 것이다. 이 원칙은 인터페이스를 더 작고 구체적인 단위로 분리함으로써, 구현 클래스가 자신과 무관한 메서드를 구현하게 하는 것을 방지한다.

     

    게임 개발을 예로 들 때, 이 원칙을 지키지 않은 코드와 이를 지킨 코드로 비교해보자.

     

     

    ISP를 지키지 않은 코드 예시

    게임에 다양한 종류의 캐릭터가 있고, 각 캐릭터는 걷기, 달리기, 공격하기 등의 동작을 할 수 있다고 가정해보자. 하지만 모든 캐릭터가 이 모든 동작을 할 수 있는 것은 아니다. 예를 들어, 'NPC'는 공격하기 기능이 필요 없을 수 있다. 그럼에도 불구하고, 모든 캐릭터가 같은 인터페이스를 구현하도록 하는 것은 ISP를 위반하는 것이다.

    public interface ICharacter
    {
        void Walk();
        void Run();
        void Attack();
    }
    
    public class Hero : ICharacter
    {
        public void Walk() { /* 구현 */ }
        public void Run() { /* 구현 */ }
        public void Attack() { /* 구현 */ }
    }
    
    public class NPC : ICharacter
    {
        public void Walk() { /* 구현 */ }
        public void Run() { /* 구현 */ }
        // NPC는 공격하지 않아야 하므로, 이 메서드는 필요 없거나 빈 구현을 해야 함
        public void Attack() { /* 빈 구현 */ }
    }
    
    

     

    ISP를 지킨 코드 예시

    ISP를 지키기 위해서는 각 기능별로 인터페이스를 분리하여, 각 캐릭터 클래스가 필요한 인터페이스만 구현하도록 해야 한다.

    public interface IWalker
    {
        void Walk();
    }
    
    public interface IRunner
    {
        void Run();
    }
    
    public interface IAttacker
    {
        void Attack();
    }
    
    public class Hero : IWalker, IRunner, IAttacker
    {
        public void Walk() { /* 구현 */ }
        public void Run() { /* 구현 */ }
        public void Attack() { /* 구현 */ }
    }
    
    public class NPC : IWalker, IRunner
    {
        public void Walk() { /* 구현 */ }
        public void Run() { /* 구현 */ }
        // NPC는 공격 기능이 필요 없으므로 IAttacker 인터페이스를 구현하지 않음
    }

     

    위의 예시에서는 ISP를 적용하여 각 캐릭터가 필요한 기능만을 가진 인터페이스를 구현하도록 했다. 이로 인해 코드는 더 유연해지고, 변경에 더 강해진다. 캐릭터가 추가되거나 기능이 변동되어도 다른 캐릭터에 영향을 미치지 않으며, 필요한 기능만을 구현함으로써 코드의 명확성과 유지보수성이 향상된다.