객체지향 5원칙(SOLID) - 인터페이스 분리 원칙

2022. 2. 15. 16:56PHP

객체지향 5원칙

올바른 객체지향 설계를 위해 수립한 원칙이 있으며, 이 다섯 가지의 원칙을 통틀어 객체지향 5원칙(SOLID)이라 명명한다. 필수로 적용하지 않지만, 적어도 이 규칙을 준수하면 준수할 수록 올바르게 설계된 객체지향이라 할 수 있습니다.

 

이 다섯 가지 원칙은 아래와 같습니다.

1. 단일 책임 원칙 (Single Responsibility Principle)

2. 개방 폐쇄 원칙 (Open-Closed Principle)

3. 리스코프 치환 원칙 (Liskov Substitution Principle)

4. 인터페이스 분리 원칙 (Interface Segregation Principle)

5. 의존성 역전 원칙 (Dependency Inversion Principle)

 

각 원칙의 영어 앞글자를 따서 SOLID원칙이라고 합니다.

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

인터페이스 분리 원칙이란 객체는 자신이 호출하지 않는 메소드에 의존하지 않아야한다는 원칙입니다.

구현할 객체에게 무의미한 메소드의 구현을 방지하기 위해 반드시 필요한 메소드만을 상속/구현하도록 권고하고 잇습니다. 만약 상속할 객체의 규모가 너무 크다면, 해당 객체의 메소드를 작은 인터페이스로 나누는 것이 좋습니다.

간단한 코드로 예시를 구현해보겠습니다.(PHP)

상황)

스마트폰이라는 객체가 있습니다. 이 스마트폰 객체는 비교적 최신에 나온 덕분에 일반적인 스마트폰 기능 왜에도 무선 충전, AR 뷰어, 생체인식 등의 다채로운 기능을 포함하고 있습니다.

이를 가지로 S20을 구현하면 스마트폰 객체의 동작 모두가 필요하므로 불필요한 메소드를 상속하지 않습니다. 그러나 S2를 구현할 경우, 무선 충전, 생체 인식과 같은 기능을 제공하지 않습니다. 그럼에도 불구하고 부모 객체인 스마트폰에 메소드가 포함되어 있으므로, S2 입장에서는 필요하지도 않는 기능을 구현해야 하는 낭비가 발생합니다.

 

인터페이스 분리 원칙을 지키지 않은 코드

/**
 * 스마트폰 추상 객체
 *
 * @author RWB
 * @since 2021.08.16 Mon 16:48:03
 */
abstract class SmartPhone{
    /**
     * 통화 함수
     *
     * @param number: [String] 번호
     */
    public function call($number){
        print($number." 통화 연결");
    }
    
    /**
     * 문자 메시지 전송 함수
     *
     * @param number: [String] 번호
     * @param text: [String] 내용
     */
    public function message($number, $text){
        print($number.": ".$text);
    }
    
    /**
     * 무선충전 함수
     */
    public function wirelessCharge(){
        print("무선 충전");
    }
    
    /**
     * AR 함수
     */
    public function ar(){
        print("AR 기능");
    }
    
    /**
     * 생체인식 추상 함수
     */
    abstract public function biometrics();
}

/**
 * S20 객체
 *
 * @author RWB
 * @since 2021.08.16 Mon 17:12:23
 */
class S20 extends SmartPhone{
    /**
     * 생체인식 함수
     */
    //@Override
    public function biometrics(){
        print("S20 생체인식 기능");
    }
}

/**
 * S2 객체
 *
 * @author RWB
 * @since 2021.08.16 Mon 17:13:27
 */
class S2 extends SmartPhone{
    /**
     * 무선충전 함수
     */
    //@Override
    public function wirelessCharge(){
        print("지원 불가능한 기기");
    }
    
    /**
     * AR 함수
     */
    //@Override
    public function ar(){
        print("지원 불가능한 기기");
    }
    
    /**
     * 생체인식 추상 함수
     */
    //@Override
    public function biometrics(){
        print("지원 불가능한 기기");
    }

 

위의 코드를 보게 되면 S2는 무선충전, AR, 생체인식이 지원되지 않는 기기입니다. 그럼에도 불구하고

SmartPhone의 상속으로 인해 해당 기능의 메소드를 강제를 상속받게 됩니다. 더군다나 biometrics()의 경우 추상 메소드이므로 필요하지도 않는 기능을 구현까지 해야합니다. 이러한 상속의 특징은 부모 객체의 규모가 클수록 개발 편의성이 극심히 저하됩니다.  이를 인터페이스 분리 원칙을 준수한 코드로 수정해보겠습니다.

/**
 * 스마트폰 추상 객체
 *
 * @author RWB
 * @since 2021.08.16 Mon 16:48:03
 */
class SmartPhone{
    /**
     * 통화 함수
     *
     * @param number: 번호
     */
    public function call($number){
        print($number." 통화 연결");
    }
    /**
     * 문자 메시지 전송 함수
     *
     * @param number: 번호
     * @param text: 내용
     */
    public function message($number, $text){
        print($number.": ".$text);
    }
}

/**
 * 무선충전 인터페이스
 *
 * @author RWB
 * @since 2021.08.16 Mon 18:23:33
 */
Interface WirelessChargable{
    /**
     * 무선충전 추상 함수
     */
    public function wirelessCharge();
}

/**
 * AR 인터페이스
 *
 * @author RWB
 * @since 2021.08.16 Mon 18:24:29
 */
Interface ARable{
    /**
     * AR 추상 함수
     */
    public function ar();
}
/**
 * 생체인식 인터페이스
 *
 * @author RWB
 * @since 2021.08.16 Mon 18:25:08
 */
Interface Biometricsable{
    /**
     * 생체인식 추상 함수
     */
    public function biometrics();
}

/**
 * S20 객체
 *
 * @author RWB
 * @since 2021.08.16 Mon 17:12:23
 */
class S20 extends SmartPhone implements WirelessChargable, ARable, Biometricsable{
   
    public function wirelessCharge(){
        print("무선충전 기능");
    }
    public function ar(){
        print("AR 기능");
    }
    public function biometrics(){
        print("생체인식 기능");
    }
}

/**
 * S2 객체
 *
 * @author RWB
 * @since 2021.08.16 Mon 17:13:27
 */
class S2 extends SmartPhone{
    /**
     * 무선충전 함수
     */
    //@Override
    public function message($number,$text){
        print("S2 기기 객체<br>");
        //SmartPhone 클래스의 오버라이딩
        return parent::message($number,$text);
    }
}

 

요약

S2는 특수 기능이 구현되어있지 않으므로, 기본적인 SmartPhone 객체만을 상속받아 구현했습니다.

인터페이스는 다중 상속을 지원하므로, 필요한 기능을 인터페이스로 나누면 해당 기능만을 상속받을 수 있습니다. 그 밖에 추후 업데이트 등을 통해 추가적인 기능이 탑재된다면, 같은 원리로 인터페이스를 설계해서 사용하면 필요한 객체에 필요한 기능을 쉽게 추가할 수 있습니다.

 

인터페이스 분리 원칙은 객체가 반드시 필요한 기능만을 가지도록 제한하는 원칙입니다. 불필요한 기능의 상속/구현을 최대한 방지함으로써 객체의 불필요한 책임을 제거합니다. 큰 규모의 객체는 필요에 따라 인터페이스로 잘게 나누어 확장성을 향상시킵니다.

 

참고자료

자바를 예시로 든 자료 https://blog.itcode.dev/posts/2021/08/16/interface-segregation-principle