1. SOLID 원칙

더보기

1. SOLID

 

SOLID  Eng. Kor.
SRP Single Responsibility Principle 단일 책임 원
OCP Open-Closed Principle 개방-폐쇄 원칙 
LSP Liskov Substitution Principle 리스코프 치환 원칙 
ISP Interface Segregation Principle 인터페이스 분리 원칙
DIP Dependency Inversion Principle 의존성 역전 원칙


객체지향 개념
은 추상화 → 캡슐화 → 다형성 → 상속/인터페이스 → SOLID 원칙 → 디자인 패턴  → 아치텍처 패턴 등이 서로 연결되어 있습니다.


 

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

더보기
Many client-specific interfaces are better than one general-purpose interface

 

"구현할 필요가 없는 기능을 가진, 인터페이스에 의존하도록 강요받으면 안 된다."
→ 즉, 클라이언트는 자신이 필요로 하는 메서드만 가진 작은 인터페이스에 의존해야 한다.

 

 

ISP의 주요 목표

  1. 작고 구체적인 인터페이스를 정의하여 , 사용하지 않는 메서드를 구현하지 않도록 한다.
  2. 인터페이스를 필요에 따라 분리 → 단일 책임 원칙(SRP) 강화

 

3. 참새, 팽귄 + 오리 예시

더보기

...이전 포스트의 LSP 예제를 이어 사용합니다.

 

1. 가정 (ISP 위반 사례)

  • 하나의 커다란 인터페이스에서 여러 기능을 정의하고, 모든 클래스가 이를 강제 구현
  • 클라이언트가 필요하지 않은 메서드까지 구현해야 하는 경우 발생

 

 

 

2.  ISP를 위반한 코드

using System;

namespace ISPViolationExample
{
    // ❌ 너무 많은 책임을 가지는 인터페이스 (ISP 위반)
    public interface IBird
    {
        void Eat();
        void Fly();
        void Swim();
    }

    // ❌ 참새는 수영할 수 없지만 인터페이스의 Swim()을 구현해야 함 → ISP 위반
    public class Sparrow : IBird
    {
        public void Eat()
        {
            Console.WriteLine("참새가 먹이를 먹는다.");
        }

        public void Fly()
        {
            Console.WriteLine("참새가 날아간다.");
        }

        public void Swim()
        {
            Console.WriteLine("참새는 수영할 수 없다."); // ❌ 잘못된 구현 → ISP 위반
        }
    }

    // ❌ 펭귄은 날 수 없지만 인터페이스의 Fly()를 구현해야 함 → ISP 위반
    public class Penguin : IBird
    {
        public void Eat()
        {
            Console.WriteLine("펭귄이 먹이를 먹는다.");
        }

        public void Fly()
        {
            throw new NotImplementedException("펭귄은 날 수 없습니다."); // ❌ 강제 구현 → ISP 위반
        }

        public void Swim()
        {
            Console.WriteLine("펭귄이 수영한다.");
        }
    }

    class Program
    {
        static void Main()
        {
            IBird sparrow = new Sparrow();
            sparrow.Eat();
            sparrow.Fly();  // 정상
            sparrow.Swim(); // ❌ 의미 없는 동작 수행

            IBird penguin = new Penguin();
            penguin.Eat();
            penguin.Fly();  // ❌ 런타임 오류 발생 가능 → ISP 위반
            penguin.Swim(); // 정상
        }
    }
}

 

 

 

 

3. ❌ OCP를 위반한 코드 문제점 파악

  • IBird 인터페이스에 너무 많은 기능 포함 → 클라이언트가 필요 없는 메서드를 구현해야 함
  • 펭귄은 날 수 없음에도 Fly()를 구현해야 함 → ISP 위반
  • 참새는 수영할 수 없음에도 Swim()을 구현해야 함 → ISP 위반

 

 

 

 

4. 🟢 ISP 가 지켜진 코드

using System;

namespace ISPExample
{
    // ✅ 기본 Bird 인터페이스 정의 (공통 기능만 정의)
    public interface IBird
    {
        void Eat();
    }

    // ✅ 날 수 있는 새 인터페이스 정의
    public interface IFlyable
    {
        void Fly();
    }

    // ✅ 수영할 수 있는 새 인터페이스 정의
    public interface ISwimmable
    {
        void Swim();
    }

    // ✅ 참새는 날 수 있는 새이므로 IFlyable 구현
    public class Sparrow : IBird, IFlyable
    {
        public void Eat()
        {
            Console.WriteLine("참새가 먹이를 먹는다.");
        }

        public void Fly()
        {
            Console.WriteLine("참새가 날아간다.");
        }
    }

    // ✅ 펭귄은 수영할 수 있는 새이므로 ISwimmable 구현
    public class Penguin : IBird, ISwimmable
    {
        public void Eat()
        {
            Console.WriteLine("펭귄이 먹이를 먹는다.");
        }

        public void Swim()
        {
            Console.WriteLine("펭귄이 수영한다.");
        }
    }

    // ✅ 오리는 날고 수영할 수 있으므로 두 인터페이스 모두 구현
    public class Duck : IBird, IFlyable, ISwimmable
    {
        public void Eat()
        {
            Console.WriteLine("오리가 먹이를 먹는다.");
        }

        public void Fly()
        {
            Console.WriteLine("오리가 날아간다.");
        }

        public void Swim()
        {
            Console.WriteLine("오리가 수영한다.");
        }
    }

    class Program
    {
        static void Main()
        {
            IBird sparrow = new Sparrow();
            sparrow.Eat();
            ((IFlyable)sparrow).Fly(); // 참새는 날 수 있음

            IBird penguin = new Penguin();
            penguin.Eat();
            ((ISwimmable)penguin).Swim(); // 펭귄은 수영할 수 있음

            IBird duck = new Duck();
            duck.Eat();
            ((IFlyable)duck).Fly(); // 오리는 날 수 있음
            ((ISwimmable)duck).Swim(); // 오리는 수영할 수 있음
        }
    }
}

 

 

5.  ISP를 준수한 코드에서 개선된 부분 파악

 

  • 필요한 기능별로 인터페이스를 분리
  • 날 수 있는 새는 IFlyable 인터페이스에서 정의
  • 수영할 수 있는 새는 ISwimmable 인터페이스에서 정의
  • 인터페이스를 명확하게 구분함으로써 불필요한 메서드 구현 방지

 

 

4. 과제

더보기

ISP를 준수하여, 수륙양용차를 C#으로 구현하세요.

  1. Car 클래스 → 육지에서만 동작
  2. Boat 클래스 → 물에서만 동작
  3. AmphibiousCar 클래스 → 육지와 물에서 모두 동작

 

참고 링크(Python 코드임)

https://youtu.be/WBJm4U86m5k?si=ulAkj83ULUxLDUSp