모든지 기록하자!

[Java] 추상 클래스 ( abstract class ) (예제 : AI Car) 본문

Java

[Java] 추상 클래스 ( abstract class ) (예제 : AI Car)

홍크 2021. 5. 18. 01:35
728x90

추상 클래스란?

용어 풀이로는 '구체적이지 않은 클래스'라는 뜻이며 영어로는 abstract class이다.

추상 클래스는 항상 추상 메서드를 포함한다. 추상 메서드는 구현 코드가 없다.

구현 코드가 없다는 것은 body(몸체)가 없다는 뜻이다.

int add(int x, int y){
	return x+y;   //  { } 안에 내용이 body(몸체)다.
}

추상 메서드는 abstract 예약어를 사용한다. 그리고 { } 대신 ; 를 쓴다.

abstract int add(int x, int y);

{ }를 사용한 것만으로도 메서드를 구현한 셈이기 때문에 유의하자

int add(int x, int y){ }  // X

메서드 선언의 의미

로직을 구현하는 것보다 더 중요한 것이 어떻게 구현할지를 결정하는 것이다.

이런 과정을 개발 설계라고 한다. 설계 과정은 더 복잡하고 다양한 방법이 있을 수 있다.

int add(int num1, int num2);

위 코드처럼 선언한 메서드를 보면 두 개의 정수를 입력받아 더 한 후 결과 값을 반환한다는 것을

유추할 수 있다. 메서드의 선언 부만 봐도 어떤 일을 하는 메서드인지 짐작할 수 있다.

추상 클래스 구현하기

public abstract class Computer {

	public abstract void display();
	public abstract void typing();
	
	public void turnOn() { // 공통코드
		System.out.println("전원을 켭니다.");
	}
	public void turnOff() { // 공통코드
		System.out.println("전원을 끕니다.");
	}
}

Computer를 상속받는 클래스 중 turnOn()과 turnOff() 구현 코드는 공통이다. 

하지만 display()와 typing()은 하위 클래스에 따라 구현이 달라질 수 있다.

이 두 메서드는 '구현에 대한 책임을 상속받는 클래스에 위임한다'라는 의미다.

상위 클래스에서는 하위 클래스도 공통으로 사용할 메서드를 구현하고 

하위 클래스마다 다르게 구현할 메서드는 추상 메서드로 선언해 두는 것이다.

public class DestTop extends Computer{

	@Override
	public void display() {
		System.out.println("DestTop display()"); // 추상메서드의 몸체코드 
	}
    
	@Override
	public void typing() {
		System.out.println("DestTop typing()");
	}

	public void turnOn() {
		System.out.println("DestTop turnOn()");
	}
}

상위 클래스인 Computer 클래스에 포함된 display()와 typing()을 재정의한다.

 

public abstract class NoteBook extends Computer{
	  // abstract class로 선언됨
	@Override
	public void display() {
		System.out.println("NoteBook display()");
	}
}

이 클래스에서는 상속받은 추상 메서드를 모두 구현하지 않고 display() 하나만 구현했다.

그러므로 NoteBook 클래스는 추상 메서드를 하나 가지고 있기 때문에 추상 클래스가 된다.

 

public class MyNoteBook extends NoteBook{

	@Override
	public void typing() {
		System.out.println("MyNoteBook typing()");
	}
}

NoteBook을 상속받은 MyNoteBook은 모든 추상 메서드가 구현된 클래스이므로

abstract 예약어를 사용하지 않는다.

 

추상 클래스 테스트

public class ComputerTest {

	public static void main(String[] args) {

//		Computer c1 = new Computer(); 추상 클래스는 인스턴스로 생성할 수 없다.
	    	Computer c2 = new DestTop();
//		Computer c3 = new NoteBook();
		NoteBook c4 = new MyNoteBook();
		
		c2.display();
		c2.typing();
		c4.display();
	}
}

추상 클래스는 모든 메서드가 구현되지 않았으므로 인스턴스로 생성할 수 없다.

추상 클래스에서 구현하는 메서드

추상 클래스는 상속을 하기 위해 만든 클래스이다. 추상 클래스에서 구현하는 메서드는

하위 클래스에서도 구현 내용을 공유할 메서드를 구현한다. 하위 클래스에서 내용을 다르게

구현해야 한다면 구현 내용을 추상 메서드로 남겨두고 하위 클래스에 구현을 위임 하는 것이다.

 

구현된 메서드  하위 클래스에서 공통으로 사용할 구현 코드. 하위 클래스에서 재정의 할 수도 있음
추상 메서드  하위 클래스가 어떤 클래스냐에 따라 구현코드가 달라짐

 

추상 클래스와 템플릿 메서드

템플릿( template )이란 용어를 사전에선 틀이나 견본을 뜻한다. 즉 틀이 있는 메서드라는 의미이다.

싱글톤 패턴과 같은 디자인 패턴이다. 

public abstract class Car {

	public abstract void drive(); // 추상메서드
	public abstract void stop();  // 추상메서드	
	public abstract void wiper(); // 추상메서드
    
	public void washCar() {}
	
	public void  startCar() {
		System.out.println("시동을 켭니다."); // 시동을 켜고 끄는 방법은 모든 차가 동일
	}					    // 그렇기 때문에 미리 구현했다.
	public void  turnOff() {
		System.out.println("시동을 끕니다.");
	}
	
	public final void run() {  // Car 클래스를 상속 받으면 어떤 자동차든 
		startCar();        //  모두 이 순서대로 동일한 방식으로 달린다
		drive();
		wiper();
		stop();
		washCar();
		turnOff();
	}
}

Car 클래스를 상속받는 두 클래스는 자율주행 자동차(AICar)와 일반 자동차(ManualCar)입니다.

이 클래스들은 추상 클래스 Car를 상속받았기 때문에 구현되지 않은 추상 메서드를 마저 구현해야 한다.

 

public class AICar extends Car{

	@Override
	public void drive() {
		System.out.println("자율 주행합니다.");
		System.out.println("자동차가 스스로 방향을 전환합니다.");
	}

	@Override
	public void stop() {
		System.out.println("자동차가 스스로 멈춥니다.");
	}

	@Override
	public void wiper() {
		System.out.println("날씨에 따라 자동으로 조종됩니다.");
	}

	@Override
	public void washCar() {
		System.out.println("자동으로 세차가 됩니다.");
		super.washCar();
	}
}

AICar 클래스는 Car클래스를 상속받았고 drive()와 stop(), wiper() 추상 메서드를 구현했다.

 

public class ManualCar extends Car{

	@Override
	public void drive() {
		System.out.println("사람이 운전합니다.");
		System.out.println("사람이 핸들을 조작합니다.");
	}

	@Override
	public void stop() {

		System.out.println("사람이 브레이크로 정지합니다.");
	}

	@Override
	public void wiper() {
		System.out.println("수동으로 와이퍼를 조종합니다.");
	}
}

ManualCar 클래스는 AICar클래스와 마찬가지로  Car클래스를 상속받았고

drive()와 stop(), wiper() 추상 메서드를 구현했다.

 

public class CarTest {

	public static void main(String[] args) {

		Car myCar = new ManualCar();
		myCar.run();
		System.out.println("================");
		Car yourCar = new AICar();
		yourCar.run();
	}
}

실행 결과

템플릿 메서드의 역할

run()은 Car클래스에서 이미 구현된 메서드다. 차가 어떻게 달려야 하는지를 구현해 놓았는데 작동 순서는

어느 차나 동일하다. 템플릿 메서드의 역할은 메서드 실행 순서와 시나리오를 정의하는 것이다.

템플릿 메서드에서 호출하는 메서드가 추상 메서드라면 차종에 따라 구현 내용이 바뀔 수는 있다.

하지만 시동을 켜고, 달리고, 멈추고, 시동을 끄는 시나리오는 변하지 않는다. 이런 메서드를

템플릿 메서드로 정의하는 것이다. 템플릿 메서드는 실행 순서, 즉 시나리오를 정의한 메서드이므로

바뀔 수 없다. 그래서 템플릿 메서드는 final 예약어를 사용해 선언한다. 메서드 앞에 final을 사용하면

상속받은 하위 클래스가 메서드를 재정의할 수 없다.

 

 

 

728x90
Comments