Back-end/JAVA

[JAVA] 자바의 인터페이스(interface)란? 게임으로 알아보는 사용이유

화누파더 2024. 7. 4. 12:36
반응형

인터페이스란?

자바의 인터페이스는 클래스가 지켜야할 규약이라고 할 수 있다. 인터페이스는 메서드를 정의만 하고, 구현은 하지 않습니다.

// 게임에서 사용할 유닛을 만들어야 되는데 유닛은 기본적으로 hp를 가지고 있다
interface Unit {
	void Hp();
}

// 그리고 게임 유닛의 일종인 솔져는 hp를 가지고 있다.
class Soldier implements Unit {
	
    @Override
    public void Hp() {
        System.out.println("Soldier'hp is 100");
    }
}

public class Main {
    public static void main(String[] args) {

        Unit soldier = new Soldier();
        soldier.Hp();
    }
}

물론 자바8부터는 default 로 구현후 사용하거나 static을 지정할 수동 있지만 여기서는 다루지 않겠다.

 

위와 같이 인터페이스는 기능이 추상 메서드만 있다. 그래서 이를 상속 받는 클래스에서 이를 반드시 구현해서 사용해야한다. 구현하지 않을 경우 컴파일 에러가 발생한다.(implement를 상속이라고 칭하지 않는 경우도 있지만 여기서는 상속이라고 하겠다.)

 

왜 인터페이스를 사용하는가?

하지만 위와 같이 사용하면 일반적인 상속을 사용해도 되는데 굳이 사용하는 이유를 모르겠다.

아래의 Unit 클래스를 상속받은 Soldier 클래스와 기능적 차이가 없기 때문이다.

class Unit {
    public void Hp() {};
}

class Soldier extends Unit {

    @Override
    public void Hp() {
        System.out.println("Soldier'hp is 100");
    }
}

public class Main {
    public static void main(String[] args) {

        Unit soldier = new Soldier();
        soldier.Hp();
    }
}

1. 표준화된 메서드 집합 제공

인터페이스를 상속받은 클래스를 사용한다면 인터페이스에 정의된 모든 추상 메서드를 오버라이딩해서 구현해야한다. 반면 클래스를 상속받은 클래스는 부모 클래스에 이미 기능들이 구현되어있고 자식 클래스에서 굳이 오버라이딩 하지 않아도 사용이 가능하다. 부모 클래스에서 hp가 100이라 정의하고 자식 클래스에서는 150으로 정의하기로 했다면 이를 누락하면 자식 클래스의 hp는 100으로 남아버리는 것이다.

class Unit {
    public void Hp() {
        System.out.println("hp는 100이다");
    };
}

class Soldier extends Unit {

    // 개발 미스로 누락
}

public class Main {
    public static void main(String[] args) {

        Unit soldier = new Soldier();
        soldier.Hp();
    }
}

// 결과 : hp는 100이다

즉, 인터페이스를 사용했을 때 장점은 구현되어야할 메서드가 명확히 정해진다는 것에 있다. 

 

2. 다중상속

자바에서 class에 대한 다중 상속은 지원하지 않는다. 하지만 interface에 대한 다중상속은 지원한다. 예를 들어 마린은 공중유닛과 지상유닛을 전부 공격할 수 있습니다. 그러나 파이어뱃은 지상유닛만 공격이 가능합니다. 이런식으로 유닛의 특성에 맞게 다중상속을 진행하여 유닛을 설계할 수 있다.

interface Unit {
    void Hp();
}

// 지상유닛 공격 인터페이스
interface GroundAttack {
    // 지상몹 공격
    void groundEnemyAttack();
}

// 공중유닛 공격 인터페이스
interface FlyAttack {
    // 공중몹 공격
    void flyEnemyAttack();
}

// Marin은 지상과 공중 모두를 공격할 수 있는 유닛으로 만들어야됨
class Marin implements Unit, GroundAttack, FlyAttack {
    
    @Override
    public void Hp() {
        System.out.println("Marin의 Hp는 100");
    }

    @Override
    public void groundEnemyAttack() {
        System.out.println("지상 유닛에게 데미지 100");
    }

    @Override
    public void flyEnemyAttack() {
        System.out.println("공중 유닛에게 데미지 70");
    }
}

public class Main {
    public static void main(String[] args) {

        Marin soldier = new Marin();
        soldier.Hp();
        soldier.groundEnemyAttack();
        soldier.flyEnemyAttack();
    }
}

// 결과 :
// Marin의 Hp는 100
// 지상 유닛에게 데미지 100
// 공중 유닛에게 데미지 70

 

이처럼 협업을 진행한다고 했을때 A직원은 Marin을 설계하고 B직원은 Firbat을 설계한다고 했을때 인터페이스만 정의되어 있다면 A직원은 Unit, GroundAttack, FlyAttack을 상속받은 유닛을 B직원은 Unit, GroundAttack를 상속받은 유닛을 인터페이스에 정의된 동일한 메서드를 이용하여 기능의 누락 없이 개발을 진행할 수 있게된다.

 

반응형