Java 에서 Interface 확장관련 질문 드립니다.(디자인 패턴)

조회수 2725회

디자인패턴에 관한 질문인 것 같습니다 ^

하나의 인터페이스를 여러개의 클래스가 구현하고 있는 상황에서

특정한 하나의 클래스에서 새로운 구현체를 만들어야 할 경우 (인터페이스에 새로운 메소드 추가)

어떻게 새로운 메소드를 추가할 것이며 다른 클래스에 영향을 주지 않도록 확장하는 방법은 무엇일까요??

또한, 호출방식이 변경되어도 좋지만 최대한 기존 호출방식이 변경되지 않도록 할 수 는 없을까요?

샘플코드입니다~ 굉장히 간단합니다~

public interface Phone {
    public void call();
}

public class LG implements Phone {
    @Override
    public void call(){
        System.out.println("calling...");
    }
}

public class Apple implements Phone {
    @Override
    public void call(){
        System.out.println("calling...");
    }
}

public interface Dmb {
    public List<String> channels();
}

굉장히 간단한 코드입니다.

LG 의 경우 DMB 가 존재하며, Apple 의 경우 DMB가 없다고 가정하겠습니다~

여기서 DMB라는기능을 LG에 포함시켜야 하는데 이 경우 어떤식으로 작업하는지가 궁금합니다.

기존의 호출방식입니다.

Phone phone = new Apple();
phone.call();

좀 더 나아가 LG class에서 다음과 같이 작업했다고 할 경우에 해당 메소드를 어떤식으로 호출하는지도 궁금합니다.

public class LG implements Phone, Dmb {
    @Override
    public void call(){
        System.out.println("calling...");
    }

    @Override
    public List<String> channels(){
        return new ArrayList<String>();
    }
}
  • (•́ ✖ •̀)
    알 수 없는 사용자

2 답변

  • 질문이 2가지 인것 같네요.

    • 인터페이스에 새 메소드가 추가되는 경우 해당 인터페이스를 구현하는 구현 클래스들의 변경을 어떻게 최소화 하는가?

    위 문제는 Expression_problem이라고 불립니다.

    디자인 패턴으로 위 문제를 해결하는 방법은 Visitor pattern을 사용하는 것인데, 이는 Visitor pattern에 맞춰서 코드를 변경해야 하기 때문에 불필요한 복잡도가 추가되게 됩니다.

    위 문제를 조금 더 정확하게 해결하는 방법으로는 Type Class를 사용하면 되는데 안타깝게도 자바에서는 지원되지 않습니다.

    다른 방법으로는 Java 8부터 포함된 Default method를 사용해서 기본 구현을 인터페이스에 추가하는 방법이 있습니다.

    이 방법은 기본 구현 외에 것을 하려면 다시 처음 문제로 돌아가게 됩니다.

    다음 질문은,

    • 구현체들 중 특정 인터페이스(DMB)만 구현한 클래스에서 메소드를 어떻게 호출하느냐?

    위에 다른분이 답변 주신것 처럼 캐스팅 해서 호출하는 방법이 있겠으나, 이 역시 근본적인 해결책은 아닙니다. 타입별로 분기를 를 제거하기 위해서 다형성을 사용했는데 다시 분기를 타야 하니 말이죠.

    Phone의 하위 구현체가 일부 인터페이스를 더 구현한다고 하면 이미 해당 구현체는 더이상 Phone type을 기대하는 곳에서 Dmb type의 메서드를 호출하는 것 자체가 이상한 구현으로 보입니다.

    아래 글을 읽어보시면 문제 이해와 해결에 도움이 많이 될거라 생각됩니다.

    참고: http://koerbitz.me/posts/Sum-Types-Visitors-and-the-Expression-Problem.html

    • (•́ ✖ •̀)
      알 수 없는 사용자
  • 거의 다 알고 계시는거 같은데...

    DMB가 필요할땐 Dmb 인터페이스로 캐스팅 하시면 되죠.

    ArrayList<Phone> list = new ArrayList<Phone>();
    
    list.add(new LG());
    list.add(new Apple());
    
    for(Phone phone : list) {
     if (phone instanceof Dmb) {
      Dmb dmb = (Dmb)phone;
      dmb.channels();
     }
    }
    

    ※ 코드 확인은 안했습니다.

    • (•́ ✖ •̀)
      알 수 없는 사용자

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)