본문 바로가기

Design Pattern

SOLID Principles Series 4 : Interface Segregation (인터페이스 분리 원칙)

 

SOLID Principles - Interface Segregation

소프트웨어 개발에서 SOLID 원칙 중 네 번째인 Interface Segregation(인터페이스 분리) 원칙은 인터페이스는 구체화된 인터페이스들로 나뉘어져 있어야 한다는 원칙입니다.

즉, 클라이언트는 필요한 인터페이스만 사용할 수 있어야 하며, 큰 범위의 인터페이스를 구현하지 않도록 해야 합니다.

아래의 예시 코드를 살펴보면, 축구 선수를 정의하는 FootballPlayer 프로토콜이 있고, 채택하는 클래스들은 패스, 드리블, 슛을 구현해야 합니다.

그러나 해당 예시에서는 골키퍼인 김병지를 FootballPlayer에 강제로 포함시키기 위해 divingCatch()와 goalKick() 메서드를 추가하였습니다. 이로 인해 Messi 클래스에도 이상한 상황이 발생하게 됩니다.


protocol FootballPlayer {
    func pass()
    func dribble()
    func shoot()
}

class Sonny: FootballPlayer {
    func pass() {}
    func dribble() {}
    func shoot() {}
}

class Messi: FootballPlayer {
    func pass() {}
    func dribble() {}
    func shoot() {}
}

extension FootballPlayer {
    func divingCatch() {}
    func goalKick() {}
}

let messi = Messi()
messi.divingCatch()
messi.goalKick() // 김병지를 FootballPlayer에 억지로 넣으려다보니 messi가 골킥을 차고 다이빙 캐치하는 어이없는 상황이 발생합니다.
  

이러한 상황을 해결하기 위해 인터페이스를 더 작은 개념으로 분리하는 것이 필요합니다.

예시에서는 FootballPlayer를 AttackAbility와 KeeperAbility로 분리하였습니다. 이를 통해 각 선수는 자신에게 필요한 능력을 갖추고, 불필요한 메서드를 구현할 필요가 없어집니다.


protocol FootballPlayer {
    func pass()
    func run()
}

protocol AttackAbility {
    func shoot()
    func heading()
    func dribble()
}

protocol KeeperAbility {
    func divingCatch()
    func goalKick()
}

class Sonny: FootballPlayer, AttackAbility {
    func pass() {}
    func run() {}
    func shoot() {}
    func heading() {}
    func dribble() {}
}

class 김병지: FootballPlayer, KeeperAbility, AttackAbility {
    func pass() {}
    func run() {}
    func shoot() {}
    func heading() {}
    func dribble() {}
    func divingCatch() {}
    func goalKick() {}
}

class 이운재: FootballPlayer, KeeperAbility {
    func pass() {}
    func run() {}
    func divingCatch() {}
    func goalKick() {}
}
  

이와 같이 인터페이스를 적절하게 분리하면 각각의 선수는 자신의 특성에 맞는 능력을 갖출 수 있게 됩니다.

이를 통해 SOLID의 Interface Segregation 원칙을 준수할 수 있습니다.