Abstract Class와 Interface Class

추상클래스(Abstract Class)와 인터페이스(Interface) 대해서 알아보겠습니다.

추상화에 대한 이야기는 이미 객체지향언어의 특징에서 다뤘기 때문에 간단히 설명하고 넘어간 후 추상클래스를 어떻게 만드는지에 대해서 알아보겠습니다.

추상화는 객체에서 어떤 공통된 요소들(Attribute, Method)를 추출해서 클래스를 만드는 것이라고 했습니다. 그렇다면 추상화된 클래스는 일반 클래스와는 그 성격이 어떻게 다를까요?

일반 클래스는 new 라는 명령어를 통해서 객체를 만들어 낼 수 있지만 추상클래스는 new 라는 명령어를 통해서 객체를 만들어 낼 수 없고 상속이라는 과정을 통해서 객체를 구현해야 합니다. 자바에서는 이러한 클래스를 일반 클래스와 차별적으로 abstract class라고 표현합니다. 참고로 일반 클래스는 abstract를 붙이지 않습니다.

메서드도 마찬가지입니다. 일반 메서드는 구현체가 존재하지만 추상 메서드는 구현체가 존재하지 않고 이를 상속 받는 클래스에서 구현할 수 있도록 선언만 해줍니다. 이렇게 선언만 한 메서드를 추상메서드라고 표현하며 메서드의 앞에 abstract를 붙여줍니다.

클래스를 선언할 때에 하나라도 추상메서드가 포함된 클래스는 추상클래스가 됩니다.

그러다면 추상 클래스는 왜? 그리고 언제 사용하는 것일까요?

만약 게임 캐릭터를 만든다고 가정해봅니다.
캐릭터는 여러가지가 있겠죠. 기사, 궁수, 마법사, 힐러 등…

이러한 캐릭터에서 공통적인 요소들을 만들어 낼 수 있을까요?

캐릭터의 체력, 스피드, 키, 체중, 달리기, 걷기, 점프 등의 요소들을 공통적인 요소로 만들 수 있을 것입니다. 그리고 그 요소들을 Unit 이라는 추상클래스를 만들고 모든 게임 캐릭터는 해당 유닛 클래스를 상속하도록 만들 수 있을 것입니다.

public abstract class Unit {
	private String name;
	private int point_x;
	private int point_y;
	private int stamina;
	private int height;
	private int weight;
	
	
	public Unit(String name, int x, int y) {
		this.name = name;
		this.point_x = x;
		this.point_y = y;
	}
	
	public void move(int x, int y) {
		point_x += x;
		point_y += y;
	}
	
	public String getName() {
		return name;
	}
	
	public int getPointX() {
		return point_x;
	}
	
	public int getPointY() {
		return point_y;
	}
	
	public abstract void weapon();
	public abstract void jump();
	public abstract void run();
	
}

게임 프로젝트의 설계자는 이제 각 캐릭터 개발자에게 Unit 클래스를 상속해서 각기 캐릭터를 만들라고 지시 할 수 있을 것입니다. 그렇게 된다면 각 개발자들은 각 캐릭터마다 체력, 스피드, 키, 체중 등의 요소를 지정하고 달리고, 걷고, 점프 하는 동작들을 구현할 수 있을 것입니다.

이런 설계는 개발하면서 굉장히 중요한 부분입니다.
만약 이런 부분이 없이 각가의 개발자에게 캐릭터를 만들어 내라고 한다면 아마도 많은 혼란이 있을 것입니다. 만들어진 코드도 동일한 행위를 하는 다양한 이름으로 구현될 것입니다. 또 각각의 객체에 정의하는 초기값도 역시 프로그래머 각각 정의하게 될테니 개발하는 과정에서 많은 시간과 자원이 낭비될 것입니다.

이러한 것을 방지하기 위해서 추상클래스를 정의하고 이를 상속하도록 하는 것이 프로그램의 통일성을 주는데 용이합니다.

그렇다면 인터페이스는 언제 사용하는 것일까요?

인터페이스는 추상클래스와 비슷한 점이 많습니다. 다만 차이가 있다면 인터페이스는 공통적인 객체의 정의라기 보다는 행위에 집중합니다. 즉 구현체가 같은 행위를 한다는 것을 보장한다는 것입니다.
그렇기 때문에 추상클래스는 상속이라고 표현하지만 인터페이스는 행위의 구현이라고 표현합니다.

예를 들어서… 다른 언어를 한국어로 번역을 하는 프로그램을 만들어 본다고 생각해봅니다. 설계자는 번역의 행위에 집중할 것입니다. 다른 언어를 한국어로 번역하는 행위, 한국어를 다른 어로 번역하는 행위 이렇게 행위를 정의할 것입니다. 그리고 이 두행위를 하는 인터페이스 클래스를 만듭니다.

public interface TranslateInterface {
	public String translate2korean(String sentence);
	public String translate2foreignlanguage(String sentence);
}

이 인터페이스 클래스에는 두가지 역할을 하는 메서드 외에는 존재하지 않습니다. 그리고 이 파일을 다른 개발자들에게 나눠주고 이 파일을 통해서 인터페이스의 미구현 부분을 구현(implement)하라고 할 것입니다. 개발자들은 이 파일을 통해 각각 번역기를 구현할 때에 어떻게 구현해야 하는가에 대하여 고민할 필요가 없이 translate2korean, translate2foreignlanguage 메서드를 구현할 것이며 방식 역시 각가의 메서드에 source 문장을 주고 target 언어로 리턴하는 부분을 구현하면 됩니다.

지금까지 설명드린 것처럼 인터페이스와 추상클래스는 상속(혹은 구현)하는 과정을 통해서 프로그램을 더 명식적으로 만들어주고 협업시에 효율을 높여줍니다. 코드의 유지보수나 재사용에도 큰 장점이 있습니다.