인터페이스의 장점
인터페이스를 사용하는 이유와 그 장점을 정리해보자.
1. 개발시간을 단축시킬 수 있다.
일단 인터페이스가 작성되면, 이를 사용해서 프로그램을 작성하는 것이 가능하다. 메소드를 호출하는 쪽에서는 메소드의 내용에 관계없이 선언부만 알면 되기 때문이다.
2. 표준화가 가능하다.
프로젝트에 사용되는 기본 틀을 인터페이스로 작성한 다음, 개발자들에게 인터페이스를 구현하여 프로그램을 작성하도록 함으로써 보다 일관되고 정형화된 프로그램의 개발이 가능하다.
3. 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.
서로 상속관계에 있지도 않고, 같은 조상클래스를 가지고 있지 않은 서로 아무런 관계도 없는 클래스들에게 하나의 인터페이스를 공통적으로 구현하도록 함으로써 관계를 맺어 줄 수 있다.
4. 독립적인 프로그래밍이 가능하다.
인터페이스를 이용하면 클래스의 선언과 구현을 분리시킬 수 있기 때문에 실제구현에 독립적인 프로그램을 작성하는 것이 가능하다. 이렇게 되면 한 클래스의 변경이 관련된 다른 클래스에 영향을 미치지 않는 독립적인 프로그래밍이 가능하다.
실제 실습프로그램을 통해 인터페이스의 장점을 살펴보자.
게임에 나오는 모든 유닛들의 최고 조상은 Unit클래스이고 유닛의 종류는 지상유닛과 공중유닛으로 나누어진다.
지상유닛의 조상은 GrandUnit이며, 공중유닛의 조상은 AirUnit이다.
그리고 지상유닛에는 Marine, SCV, Tank와 공중유닛에는 Dropship이 있다고 가정해보자.
SCV는 Tank와 Dropship과 같은 기계화 유닛을 수리할 수 있는 기능을 제공하기 위해 repair메소드를 정의할 것이다.
하지만 유닛은 여러개라 void repair(Tank t) 처럼 여러개의 메소드가 필요할 것이다.
또한, 공통조상의 타입인 Unit으로 정의한다고 한들, Marine같은 사람유닛은 수리할 수 있는 기능이 포함되면 안된다.
따라서 현재의 상속관계에서는 이들의 공통점은 없다.
이 때 인터페이스를 이용하면 기존의 상속체계를 유지하면서 이들 기계화 유닛에 공통점을 부여할 수 있다.
다음과 같이 Repairable이라는 인터페이스를 정의하고 수리가 가능한 기계화 유닛에게 이 인터페이스를 구현하도록 하면 된다.
interface Repairable{ }
class SCV extends GroundUnit implements Repairable{ }
class Tank extends GroundUnit implements Repairable{ }
class Dropship extends GroundUnit implements Repairable{ }
이렇게 선언해주고, repair메소드의 매개변수의 타입을 Repairable로 선언하면,
이 메소드의 매개변수로 Repairable인터페이스를 구현한 클래스의 인스턴스만 받아들여질 것이다.
앞으로 새로운 유닛이 추가되어 클래스를 추가할 때, SCV의 repair메소드에 의해서 수리가 가능하도록 하려면
Repairable인터페이스를 구현하도록 하면 될 것이다.
다음 실습프로그램을 살펴보자.
Marine은 Repairable인터페이스를 구현하지 않았으므로 SCV클래스의 repair메소드의 매개변수로 Marine을 사용하면
에러가 발생한다.
repair메소드의 매개변수 r은 Repairable타입이기 때문에 인터페이스 Repairable에 정의된 멤버만 사용할 수 있다.
그러나 Repairable에는 정의된 멤버가 없으므로 이 타입의 참조변수로는 할 수 있는 일은 아무 것도 없다.
따라서 instanceof연산자로 타입을 체크한 뒤 캐스팅하여 Unit클래스에 정의된 변수를 사용할 수 있도록 하였다.
이와 유사한 한가지 예시를 더 살펴보자.
게임에 나오는 건물들을 클래스로 표현하고 이들의 관계를 표현해보면 다음과 같다.
최고조상인 Building클래스가 있을 것이고 자손클래스이자 건물클래스인 Academy, Bunker, Barrack, Factory가 있다고 가정해보자.
이 때 Barrack과 Factory만 건물을 이동시킬 수 있는 새로운 메소드를 추가하고자 한다면 어떻게 해야 할까?
최고조상인 Building클래스에 메소드를 추가한다면, 자손클래스 모두에 상속이 되기 때문에 아닐 것이다.
이런 경우에도 인터페이스를 이용해서 해결할 수 있다.
새로 추가하고자 하는 메소드를 정의하는 인터페이스를 정의하고 Barrack과 Factory클래스로 구현하면 해결이 가능하다.
인터페이스의 이해
인터페이스의 본질적인 측면에 대해 살펴보자.
먼저 인터페이스를 이해하기 위해서는 다음의 두 가지 사항을 반드시 염두에 두고 있어야 한다.
-클래스를 사용하는 쪽과 클래스를 제공하는 쪽이 있다.
-메소드를 사용하는 쪽에서는 사용하려는 메소드의 선언부만 알면 된다.
다음 간단한 예시를 살펴보자.
클래스 A는 클래스 B의 인스턴스를 생성하고 메소드를 호출한다.
이 두 클래스는 서로 직접적인 관계에 있다.
이 경우 클래스 A를 작성하려면 B가 이미 작성되어 있어야 한다.
그리고 클래스 B의 methodB()의 선언부가 변경되면, 이를 사용하는 클래스 A도 변경되어야 한다.
이와 같이 직접적인 관계의 두 클래스는 한 쪽이 변경되면 다른 한쪽도 변경되어야 한다는 단점이 있다.
그러나 클래스 A가 클래스 B를 직접 호출하지 않고 인터페이스를 매개체로 해서 클래스 A가 인터페이스를 통해서
클래스 B의 메소드에 접근하도록 하면, 클래스 B에 변경사항이 생기거나 클래스 B와 같은 기능의 다른 클래스로 대체 되어도 클래스 A는 전혀 영향을 받지 않도록 하는 것이 가능하다.
다음과 같이 인터페이스를 선언해주자.
interface I {
public abstract void methodB() ;
}
그 다음에는 클래스 B가 인터페이스 I를 구현하도록 한다.
class B implements I{
public void methodB() {
System.out.println(" ");
}
}
이제 클래스 A는 methodA(I i) { i.methodB() ; } 이렇게 B대신 인터페이스 I를 사용해서 작성할 수 있다.
이렇게 되면 직접적인 관계에서 간접적인 관계로 바뀐것이다.
결국 클래스 A는 여전히 클래스 B의 메소드를 호출하지만, 클래스 A는 인터페이스 I하고만 직접적인 관계에 있기 때문에 클래스 B의 변경에 영향을 받지 않는다.
'JAVA > Basic' 카테고리의 다른 글
[JAVA-basic] default 메소드와 static 메소드 (0) | 2021.09.12 |
---|---|
[JAVA-basic] 인터페이스 (0) | 2021.08.31 |
[JAVA-basic] 추상클래스 (0) | 2021.08.27 |
[JAVA-basic] 다형성(2) (0) | 2021.08.24 |
[JAVA-basic] 다형성 (0) | 2021.08.24 |