본문 바로가기

Language/Java

추상 (Abstract) 클래스 와 인터페이스 (Interface)의 사용 목적과 차이점

반응형

이번 글에서는 자바에서 사용하는 추상 클래스 (Abstract Class) 인터페이스 (Interface) 차이점과 두 가지의 사용 목적에 대해 정리를 해보겠습니다. 

 

 

먼저 추상 클래스의 개념에 대한 정리를 하겠습니다. 

 

1. 추상 클래스 (Abstract Class)

 

추상클래스는 실체 클래스의 공통적인 부분을 추출해서 선언한 클래스를 의미하며 실체성이 없고 구체적이지 않기 때문에 객체를 생성할 수 없다. 때문에 실체클래스와의 상속 관계를 통해 사용할 수 있다. 

 

추상화에서 추상화는 클래스간의 공통점을 찾아내서 공통의 부모를 설계하는 작업을 의미합니다.

 

비유하자면 추상클래스는 미완성 설계도라고 할 수 있다. 

 

자바에서 사용 방법은 다음과 같습니다. 

 

[접근 제한자] abstract class [클래스명] {

// 추상 메서드
	abstract [void | return type] [메서드명] {}

// 일반 메서드
	[void | return type] [메서드명] {
    	// 특정 기능
    }
	
}

클래스를 생성할 때 class 앞에 abstract 를 넣어주면 추상크래스를 생성할 수 있습니다. 

 

추상 클래스는 일반 클래스의 차이점은 추상 메서드를 사용할 수 있다는 점이고 나머지는 일반 클래스와 모두 동일합니다. 

 

그럼 굳이 추상 메서드를 사용하는 목적이 있을 텐데 그 이유는 나중에 다루도록 하겠습니다. 

 

 

2. 인터페이스 (Interface)

 

인터페이스는 모든 메서드가 추상 메서드인 경우를 말하며 추상 클래스보다 한 단계 더 추상화된 클래스라고 볼 수 있다.

 

비유 하자면 추상클래스는 미완성 설계도 이고, 인터페이스는 설계도를 그리기위한 요구사항 명세서라고 할 수 있다 . 

 

인터페이스는 고유한 특징이 있습니다. 자바에서는 일반적으로 다중 상속을 허용하지 않지만 인터페이스는 가능합니다.

예를 들어 보겠습니다. 

 

// Break
public class Break {
	public void work(){
    	System.out.println("브레이크가 작동한다.");
    }
}

// Engine
public class Engine {
	public void work(){
    	System.out.println("엔진이 작동한다.");
    }
}

// Car
public class Car extends Break, Engine(
	public static void main(String [] args) {
    	super.work();
    }
}

만약 클래스 간에 다중 상속을 허용한다면 Car 클래스는 work() 라는 메서드의 사용을 Break에서 할지 Engine에서 사용할지 모호함이 발생합니다. 자바는 기본적으로 모호함을 싫어 하기 때문에 애초에 클래스간에 다중 상속을 지원하지 않습니다. 

 

하지만 Interface에서는 다중 상속을 허용합니다. 

 

// Break
public interface Break {
	public abstract void work();
}

// Engine
public interface Engine {
	public abstract void work();
}

// Car
public class Car implements Break, Engine(
	public void work(){
    	System.out.println("자동차에서 엔진과 브레이크가 작동한다");
    }
}

// Airplane
public class Airplane implements Break, Engine(
	public void work(){
          System.out.println("비행기에서 엔진과 브레이크가 작동한다.");
    }
}

 

다중 상속을 허용 할 수 있는 가장 큰 이유는 인터페이스의 문법적 특징 때문입니다. 

 

자바에서 인터페이스 내에 멤버 변수는 static final이 default로 설정 되어 있기 때문에 해당 인터페이스를 사용하는 클래스에서 인터페이스 내의 멤버변수를 변경하는 것은 불가능 합니다. 

 

또한 인터페이스 내부의 모든 메서드는 추상 메서드를 사용해야 하기 때문에 다중 상속을 하더라도 메서등의 특정 기능이 모든 인터페이스에 설정 되어 있지 않기 때문에 사용 출처에 대한 모호성이 발생하지 않는다. 

 

 

 

3. 추상 클래스와 인터페이스를 사용하는 목적

 

두 가지를 사용 하는 목적에 대해 정리 하기 위해 한 가지 예시를 들어 보겠습니다. 

 

게임을 개발 한다고 가정해 보겠습니다

// Unit이 Monster를 공격함
public interface Attack {
    public abstract int attack(int weapon, Monster monster);
}

// Monster가 Unit을 공격함
public interface Defense {
    public abstract int defense(int weapon, Unit unit);
}

// Unit들이 공통적으로 수행하는 행동
public abstract class Action {
	public int walk(){
    	return 10;
    }
    public abstract void hello();
}

public class Unit () {
	public int hp;
}

public class Monster() {
	public int hp;
}
public class Soilder extends Action implements Attack, Defense{    
	public int attack(int weapon, Monster monster){
		int total_hp = monster.hp;
        total_hp -= weapon;
    	return total_hp;    
    }
    
    public int defense(int weapon, Unit unit) {
    	int total_hp = unit.hp;
        total_hp -= weapon;
        return total_hp;
    }
    
    public void hello() {
    	System.out.println('군인입니다.');
    }
}

public class Healer extends Action implements Attack, Defense{    
	public int attack(int weapon, Monster monster){
    	return monster.hp;
    }
    
    public int defense(int weapon, Unit unit) {
    	int total_hp = unit.hp;
        total_hp -= weapon;
        return total_hp;
    }
    
    public void hello() {
    	System.out.println('힐러입니다.');
    }
}

 

만약 모든 클래스가 인터페이스를 사용해서 기본 틀을 구성한다면 공통으로 필요한 모든 기능들도 모든 클래스에서 오버라이딩 하여 재정의 해야 하는 번거로움이 있습니다. 

 

위의 예시에서 attack(), defense() 같은 경우에 해당하는 거죠

 

이렇게 공통된 기능이 필요 하다면 추상 클래스를 이용해 일반 메서드를 작성하여 자식 클래스에서 사용할 수도 있도록 하면 안되는가? 하는 물음이 생길 수 있습니다. 

 

이전에 추상 클래스의 특징은 '다중 상속'이 불가능 하다고 했습니다. 만약 각각 인터페이스에서 공통된 기능을 수행하고자 할 때는 인터페이스로 구현하는것이 더 효과적일 것입니다. 

 

 

제 나름대로의 생각이지만 추상 클래스와 인터페이스를 사용하는 각각의 경우에 대해 정리 하겠습니다. 

 

"상속을 받아 기능을 확장하고자 할때는 추상 클래스를 사용하고 동일한 기능을 구현하는 클래스간의 메서드나 변수의 이름을 통일하고자 할 때는 인터페이스를 사용한다."

 

무엇보다 상황에 맞게 "잘" 사용하는 것이 중요합니다.

반응형