백엔드 개발 공부 일지
JAVA Basic - 추상 클래스 본문
● 추상 클래스
추상클래스?
내가 지금까지 구현한 모든 클래스는 concrete 클래스이다.
추상클래스란, 하나 이상의 추상 메소드를 포함한 클래스를 추상 클래스(abstract class)라고 합니다.
단 하나 이상의 추상 메서드만 포함하면 되며 생성자, 일반 메서드도 포함 가능합니다.
추상클래스와 인터페이스의 다른 점은 인터페이스는 추상메서드"만" 포함하나,
추상 클래스는 하나의 추상 메서드만 포함하면 추상클래스가 됩니다.
이 때 추상 메서드란, 함수 선언만 되어있고 구현부가 없는 메서드를 추상 메서드라고 합니다.
추상 클래스는 "다형성"을 보장하기 위해 나타난 개념인데요.
"자식 클래스에서 반드시 재정의가 되어야 된다"는 점에서 다형성이 보장됩니다.
부모 클래스에서 추상 메서드를 선언하면, 자식 클래스는 부모의 추상적 메서드를 상속받아 메서드를 구현해 그 기능들을 구현 가능한데요. 이 때 부모가 가진 추상 메소드들을 자식 클래스에서 반드시 재정의(오버라이딩)해야 합니다. 즉 부모가 자식에게 명령을 내렸을 때 자식 클래스가 반드시 동작되도록 재정의한다는 점에서 다형성이 보장됩니다.
추상클래스는 인스턴스 생성을 할 수 없다.
● 템플릿 메서드
템플릿 메서드는 디자인 패턴의 한 방법으로 모든 객체 지향 프로그램에서 사용하는 구현 방법이다.
(자바 뿐 아니라 C++, C# 에서도 동일하게 적용)
추상클래스를 활용하면 이 템플릿 메서드를 구현할 수 있다.
아래는 템플릿 메서드의 예제이다.
Car라는 추상클래스 안의 startCar, turnOff, run이라는 메서드를 구체적으로 구현하고 drive와 stop을 추상 메서드로 구현하였다.
package template;
public abstract class Car {
public abstract void drive();
public abstract void stop();
public void startCar() {
System.out.println("시동을 켭니다.");
}
public void turnOff() {
System.out.println("시동을 끕니다.");
}
// 탬플릿 메서드 시작
final public void run() {
startCar();
drive();
stop();
turnOff();
}
}
여기서는 시동을 켜고끄고는 모든 차가 동일하다고 보았고 핸들에 따라 달라질 수 있는 운전에 대한 부분을 추상메서드로 추상클래스 내에 구현하고 상속받아 구현하는것을 목표로 한다.
아래의 예제에서 AICar와 ManualCar 예제를 살펴보자.
package template;
public class AICar extends Car {
@Override
public void drive(){
System.out.println("자율 주행합니다.");
}
@Override
public void stop(){
System.out.println("스스로 멈춥니다.");
}
}
package template;
public class ManualCar extends Car{
@Override
public void drive(){
System.out.println("사람이 운전한다.");
}
@Override
public void stop(){
System.out.println("브레이크로 멈춘다.");
}
}
다음은 실행결과 이다.
package template;
public class CarTest {
public static void main(String[] args) {
System.out.println("==AICar==");
Car mycar = new AICar();
mycar.run();
System.out.println("==ManualCar==");
Car hiscar = new ManualCar();
hiscar.run();
}
}
==AICar==
시동을 켭니다.
자율 주행합니다.
스스로 멈춥니다.
시동을 끕니다.
==ManualCar==
시동을 켭니다.
사람이 운전한다.
브레이크로 멈춘다.
시동을 끕니다.
이렇게 템플릿 메서드의 역할은 "메서드 실행 순서와 시나리오를 정의하는 것"이다. 다시말해, 로직흐름을 정의한다.
상위 추상클래스에서는 하위클래스가 공통으로 사용하는 코드를 변경하면 안되기 때문에 final로 메서드를 선언한다.
● 템플릿 메서드 응용
다음 예제는 템플릿 메서드를 응용한 게임프로그램 예제이다.
플레이어는 레벨에 따라 run, jump turn이 제한적으로 가능하고 이것을 추상화 클래스 내의 템플릿 메서드를 활용하여 각각의 세부 행동을 클래스 상속을 통해 구현한 모습이다.
package gamelevel;
public class Player {
private PlayerLevel level; // Player가 가지는 level 변수 선언
//디폴트 생성자, 처음 생성되면 비기너 레벨로 시작하며 레벨 메세지 출력
public Player() {
level = new BeginnerLevel();
level.showLevelMessage();
}
public PlayerLevel getLevel() {
return level;
}
public void upgradeLevel(PlayerLevel level) {
this.level = level;
level.showLevelMessage();
}
public void play(int count) {
level.go(count);
}
}
package gamelevel;
public abstract class PlayerLevel {
public abstract void run();
public abstract void jump();
public abstract void turn();
public abstract void showLevelMessage();
final public void go(int count) {
run();
for (int i = 0; i < count; i++) {
jump();
}
turn();
}
}
package gamelevel;
public class BeginnerLevel extends PlayerLevel {
@Override
public void run() {
System.out.println("천천히 달립니다.");
}
@Override
public void jump() {
System.out.println("jump 불가");
}
@Override
public void turn() {
System.out.println("turn 불가");
}
@Override
public void showLevelMessage() {
System.out.println("***** 초보자 레벨 *****");
}
}
package gamelevel;
public class AdvancedLevel extends PlayerLevel {
@Override
public void run() {
System.out.println("빨리 달립니다.");
}
@Override
public void jump() {
System.out.println("높이 jump 합니다");
}
@Override
public void turn() {
System.out.println("turn 불가");
}
@Override
public void showLevelMessage() {
System.out.println("***** 중급자 레벨 *****");
}
}
package gamelevel;
public class SuperLevel extends PlayerLevel {
@Override
public void run() {
System.out.println("매우 빨리 달립니다.");
}
@Override
public void jump() {
System.out.println("매우 높이 jump 합니다");
}
@Override
public void turn() {
System.out.println("한바퀴 돕니다");
}
@Override
public void showLevelMessage() {
System.out.println("***** 고급자 레벨 *****");
}
}
package gamelevel;
public class MainBoard {
public static void main(String[] args) {
Player player = new Player();
player.play(1);
AdvancedLevel aLevel = new AdvancedLevel();
player.upgradeLevel(aLevel);
player.play(2);
SuperLevel sLevel = new SuperLevel();
player.upgradeLevel(sLevel);
player.play(3);
}
}
***** 초보자 레벨 *****
천천히 달립니다.
jump 불가
turn 불가
***** 중급자 레벨 *****
빨리 달립니다.
높이 jump 합니다
높이 jump 합니다
turn 불가
***** 고급자 레벨 *****
매우 빨리 달립니다.
매우 높이 jump 합니다
매우 높이 jump 합니다
매우 높이 jump 합니다
한바퀴 돕니다
Process finished with exit code 0
● final 예약어
템플릿 메서드는 대개 'final' 예약어를 함꼐 사용한다. final메서더의 경우 모든 클래스에 대하여 공통으로 수행되는 부분이고 더이상 수정이 필요하지 않는 메서드를 포함하고 있기 때문이다.
final 예약어는 마지막으로 정한것으로 더이상 수정이 불가능하다는것을 의미한다.
변수, 메서드, 클래스 모두한테 사용이 가능한 예약어이며 다음과 같이 사용 위치에 따른 이유를 가지고 있다.
변수 : final 변수는 상수를 의미한다.
메서드 : final 메서드는 하위 클래스에서 재 정의 할 수 없다.
클래스 : final 클래스는 상속할 수 없다.
'Java 입문' 카테고리의 다른 글
JAVA Basic - 기본 클래스 (0) | 2022.12.12 |
---|---|
JAVA Basic - 인터페이스 (0) | 2022.12.08 |
JAVA Basic - 상속 (0) | 2022.12.07 |
JAVA Basic - 배열 (0) | 2022.11.28 |
JAVA Basic - CLASS와 객체 2 (0) | 2022.11.26 |