해결된 질문
작성
·
532
2
제가 정리한 내용은
추상클래스는 new 클래스를 통해 직접 객체를 생성할 수 없으며, 상속을 위한 클래스이고
인터페이스는 구현체에 대한 메소드를 오버라이드 하는 것으로 이해하였는데..
첫번째 질문은 두 개의 역할이 중복되는 것이 아닌지에 대한 질문입니다. 두 개의 역할 모두 구현체에게 메소드를 주입하는 것인데 굳이 구분한 것인지에 대한 질문입니다.
두번째 질문은 일반 클래스의 상속이 있는데 굳이 추상클래스를 사용 하는 점 입니다. 제 생각으로는 부모 객체의 사용을 막기 위해 추상클래스로 변경을 한 것인지? 아니면 다른 이유가 있는 것인지에 대해서도 궁금합니다.
답변 1
1
안녕하세요?
추상클래스를 상속하거나 인터페이스를 구현하는 클래스는 반드시 각각에 선언된 추상메소드를 구현해야 합니다. 이렇게만 보면 둘은 비슷한데 왜 굳이 구분했는지 조금 의아할 수 있습니다.
예를 들어볼게요.
취업 준비생들끼리 팀을 이루어 면접 스터디를 진행한다고 가정하겠습니다. 그 중에 한명이 토론 면접에서 높은 점수를 받기 위한 팁을 알아왔다며 팀원들에게 아래와 같이 공유하였습니다.
토론 면접 팁 : 상대방의 발언이 끝나면 반드시 '잘 들었다'는 멘트를 먼저 하기
예1)
(필수) XXX 님의 말씀 잘 들었습니다.
(반론) 저는 생각이 조금 다른데요 ...
예2)
(필수) XXX 님의 말씀 잘 들었습니다.
(반론) 그 부분에 대해서는 저도 일부 동의하지만...
그러면 팀원들은 이 내용을 잘 기억해뒀다가 토론 면접에서 반드시 (필수) 멘트를 먼저 하고 나서 상대방에게 반론을 하게 될 것입니다. 여기서 (필수) 멘트에 해당하는 것은 모든 반론 앞에 공통적으로 들어가는 부분인데 이를 클래스로 만들면 아마 이렇게 추상 클래스로 만들 수 있을 겁니다.
public abstract class 토론면접 {
public void 필수() {
System.out.println("XXX 님의 말씀 잘 들었습니다.");
}
public abstract void 반론();
}
그리고 이 클래스를 상속하는 2개의 클래스는 다음과 같이 반론 메소드를 만들 수 있겠죠.
public class 토론면접_예1 extends 토론면접 {
@Override
public void 반론() {
System.out.println("저는 생각이 조금 다른데요 ...");
}
}
public class 토론면접_예2 extends 토론면접 {
@Override
public void 반론() {
System.out.println("그 부분에 대해서는 저도 일부 동의하지만...");
}
}
이 클래스들로부터 만들어진 객체를 이용할 때는 이런 순서로 각 메소드를 호출하게 될 것입니다.
토론면접객체.필수(); // 필수 멘트
토론면접객체.반론(); // 반론 멘트
그러면 필수 멘트는 기본으로 하고 반론 멘트를 이어서 하게 되겠죠.
이처럼 추상 클래스는 공통되는 부분을 모아서 추상 클래스에 정의하고, 그 외의 부분을 자식 클래스에서 확장하여 사용하는 개념으로 보시면 좋습니다. 단, 일반 상속과는 다르게 반드시 구현을 필요로 하는 추상 메소드가 존재할 수 있으므로 추상 클래스만으로는 객체를 생성할 수 없지요.
이번에는 다른 예를 들어볼까요? 우리 주변에서 카페는 굉장히 많이 찾을 수 있습니다. 카페에 가면 먼저 음료를 주문하고 자리에 착석 또는 근처에서 대기하다가 음료가 나오면 받아서 자리로 이동 후 한동안 시간을 가지고 나서 음료를 반납하고 퇴장합니다. 고객 입장에서는 이렇지만 카페 직원 입장은 순서가 조금 다를 수 있는데, 간단히 아래와 같다고 해보겠습니다.
1) 음료 주문
2) 음료 제작
3) 주문 고객 호출
1) 먼저 고객으로부터 음료를 주문받습니다. 그런데 카페마다 주문받는 방법은 다를 수 있겠죠. 직원분이 직접 주문을 받을 수도 있고 키오스크를 통해서 주문받도록 할 수도 있고 모바일 앱을 통해 주문받을 수도 있을 겁니다. 어찌됐건 음료를 주문받는다는 건 동일하죠.
2) 그 다음에는 음료를 제작합니다. 음료 제작 방법도 다양한데요. 이미 다 되어 있는 음료를 컵에 따라주기만 할 수도 있고 기계를 이용해서 즉석으로 음료를 만들 수도 있고 드립 커피 등등 주문 음료마다, 가게마다 방식이 조금씩 다를겁니다. 어찌됐건 음료를 제작한다는 건 동일하죠.
3) 음료가 준비되면 주문 고객을 호출합니다. 주문 고객 호출 방법도 다양한데요. 커다란 TV 에 주문번호를 보여줄 수도 있고 진동벨을 울릴 수도 있고 모바일 앱으로 안내할 수도 있고 직접 직원분이 큰 목소리로 고객을 호출할 수도 있을 겁니다. 어찌됐건 주문 고객을 호출한다는 건 동일하죠.
이처럼 음료 주문, 제작, 고객 호출의 방법은 카페마다 서로 다를 수 있지만 어찌됐건 음료를 주문받고, 주문받은 음료를 제작하고, 고객을 호출한다는 것은 같습니다. 즉, 카페마다 공통적으로 뭔가를 하는 것 대신 각자의 방식대로 같은 목적을 달성하는거죠. 이 상황을 인터페이스로 만들면 이렇게 될 수 있겠네요.
public interface 카페 {
void order(); // 음료 주문
void make(); // 음료 제작
void call(); // 주문 고객 호출
}
그러면 이 인터페이스를 구현하는 클래스는 저마다의 방식으로 동작을 정의할 겁니다.
public class 카페_예1 implements 카페 {
@Override
public void order() {
System.out.println("키오스크로 주문받습니다.");
}
@Override
public void make() {
System.out.println("기계로 음료를 제작합니다.");
}
@Override
public void call() {
System.out.println("진동벨로 안내합니다.");
}
}
public class 카페_예2 implements 카페 {
@Override
public void order() {
System.out.println("직원분이 직접 주문받습니다.");
}
@Override
public void make() {
System.out.println("직원분이 직접 음료를 제작합니다.");
}
@Override
public void call() {
System.out.println("직원분이 직접 호출합니다.");
}
}
서로의 구체적인 동작은 다르지만 적어도 '카페' 라는 인터페이스를 구현하면 모두 동일한 목적을 가지는 order(), make(), call() 이라는 동작이 준비가 되겠지요. 이처럼 인터페이스는 이를 구현하는 모든 클래스들이 저마다의 방식으로 같은 동작을 약속합니다. 그리고 추상클래스와는 다르게 인터페이스는 다중상속이 가능하죠.
설명을 적다보니 다소 길어졌는데 각 상황에서 추상클래스와 인터페이스가 어떻게 서로 다른 용도로 쓰일 수 있는지 이해하시는데 도움되면 좋겠습니다.
감사합니다 😊
이해했습니다!! 추상클래스와 인터페이스 각각의 목적에 맞게 잘 사용해보겠습니다!