우리는 지금까지 추상 클래스의 개념과 사용법에 대해서 살펴보았습니다. 이제 메서드 사용과 관련된 내용을 좀 더 구체화시켜서 살펴보도록 하겠습니다. 만일, 추상 클래스를 사용할 때 모든 실체(자식) 클래스가 추상(부모) 클래스에 선언된 메서드를 그대로 사용한다면 큰 문제가 없을 것입니다.
하지만, 실체 클래스에서 각각 메서드가 조금씩 다른 동작을 해야 한다면? 문제가 됩니다. 예를 들어, 알아서 실체 클래스에서 메서드를 선언해서 정의하라고 할 경우에는 우리가 추상 클래스를 만드는 목적처럼 각각 메서드 이름이 제멋대로 선언될 가능성도 있습니다. 혹은, 실수로 해당 메서드를 빼먹는 실수를 할 수도 있지요.
물론 '추상 클래스에서 메서드를 선언해두고, 실체 클래스에서 알아서 오버라이드 하면 해결되는 문제 아닌가요?'라고 말할수도 있겠습니다. 맞습니다! 그렇게 구현할 수도 있습니다. 하지만 여기서 중요한 지점은 역시 설계의 관점에서의 문제입니다.
우리가 AI인형 모듈을 설계하였는데, 이 모듈로 인형을 만들 때 인사를 하는 기능이 기본적으로 모두 탑재하기를 원하고 있습니다. 캐릭터 인형들이 각각 자신의 방식으로 인사를 하도록 설계를 해야 하는 것이죠. 그러나 추상 클래스 레벨에서 별다른 동작을 지정하고 싶지는 않습니다. '이 모듈로 인형을 만들 때는, 반드시 인사를 하는 기능을 넣어야 해!'라고 말하고 싶은 것이죠. 반드시 해당 모듈을 사용하는 인형들은 sayHello( )라는 메서드를 "반드시" 넣어야 하는 상황인 것입니다.
이 sayHello( )라는 메서드는 추상 클래스에서 만들라고 강요하고 싶지만, 추상 클래스에서는 메서드 이름만 정해놓고 실제 동작은 실체 클래스에서 알아서 오버라이드를 통해 구현하도록 만들고 싶은 것입니다.
이럴 때 우리는 여기서 "추상 메서드"를 사용하게 됩니다.
추상 클래스를 설계할 때, 실체 클래스개 실행 내용 즉 메서드를 선언하기를 강요하고 싶다면 이 추상 메서드를 선언하여 주면 됩니다.
추상 메서드는...
- 추상 클래스 내에서만 선언할 수 있고
- 메서드의 선언부만 있으며
- 메서드 실행 내용인 중괄호( { } )가 없습니다.
[public | protected] abstract 리턴타입 메서드명(파라미터,...);
// 예시
public abstract class RagDoll {
public abstract void sayHello();
}
위와 같이, RagDoll이라는 추상 클래스에서 추상 메서드로 sayHello( )를 선언해 두었습니다. 이제 위 추상 클래스를 상속하는 실체 클래스들은 반드시 sayHello( )라는 메서드를 오버라이드로 구현해야 하는 조건이 강제됩니다.
이제 예제 코드를 작성해 보면서 추상 메서드 적용 사례를 살펴보도록 하겠습니다.
public abstract class RagDoll {
public String product;
public void turnOn() {
System.out.println("동작을 시작합니다");
}
public abstract void sayHello();
}
추상 클래스 RagDoll을 선언했습니다. 필드에 product, 메서드 turnOn이 선언되었습니다. 그리고 추상 메서드 sayHello가 선언되어 있습니다.
public class Barbie extends RagDoll {
public Barbie() {
this.product = "Barbie Doll";
}
@Override
public void sayHello() {
System.out.println("Hello! I'm Barbie!");
}
}
public class Mimi extends RagDoll {
public Mimi() {
this.product = "Mimi Doll";
}
@Override
public void sayHello() {
System.out.println("Hi~~ I'm Mimi.");
}
}
이제 실행 클래스에서, 이 추상 클래스 기반의 구조를 여러 가지 방식으로 실행해 보도록 하겠습니다.
public class ExampleMain {
public static void ragDollHello(RagDoll ragDoll) {
ragDoll.sayHello();
}
public static void main(String[] args) {
// 1. 인스턴스 직접 생성 방식
Barbie barbie = new Barbie();
Mimi mimi = new Mimi();
barbie.sayHello();
mimi.sayHello();
System.out.println("----------------");
// 2. 자동 타입 변환 방식
RagDoll ragDoll = new Barbie();
ragDoll.sayHello();
ragDoll = new Mimi();
mimi.sayHello();
System.out.println("-----------------");
// 3. 메서드의 다형성
ragDollHello(new Barbie());
ragDollHello(new Mimi());
}
}
'Programming > JAVA' 카테고리의 다른 글
인터페이스(2) - 인터페이스의 선언과 구성 멤버의 특성 (0) | 2023.03.15 |
---|---|
인터페이스(1) - 인터페이스의 역할 (0) | 2023.03.13 |
상속(12) - 추상 클래스 2 (0) | 2023.03.10 |
상속(12) - 추상 클래스 1 (0) | 2023.03.10 |
상속(11) - 객체의 타입 확인(instanceof) (0) | 2023.03.09 |