서로 다른 장치들이 연결되어 상호 데이터를 주고 받는 규격을 의미한다.
하드웨어 장치를 생각해보자.
서로 다른 pc 를 사용하지만 usb 를 연결하는 장치는 동일하다.
안드로이드 폰을 이용하면 다른 기종이라 하더라도 같은 종류의 충전 장치를 가진다.
소프트웨어에서의 인터페이스도 비슷하다.
서로 다른 클래스를 연결할 때 규격이 존재한다면 클래스들이 잘 접속할 수 있을 것이다. 이 규격이 인터페이스다.
인터페이스 정의
interface RemoteControl { public abstract void on(); // public abstract 생략가능 void off(); }
추상 클래스와 동일한 문법으로 정의할 수 있다.
만약 서로 다른 리모컨을 만든다고 가정을 해보자.
각기 다른 회사에서 리모컨을 만든다면 각자의 코드를 만들게 될 것이다.
class Rmc1 { public void on() { System.out.println("Rmc1 리모컨이 켜집니다"); } public void off() { System.out.println("Rmc1 리모컨이 꺼집니다"); } } class Rmc2 { public void hello() { System.out.println("Rmc2 리모컨이 켜집니다"); } public void bye() { System.out.println("Rmc2 리모컨이 꺼집니다"); }
이런 코드로 작성이 되면 각 제조사들 간의 가전제품에서는 사용가능할 수 있으나, 만능 리모컨이나 다양한 가전제품을 연결해서 사용하는 홈네트워크 서버 등에는 활용이 어려울 것이다.
그래서 이 사이에 합의가 필요한데 이때 인터페이스를 사용하고, 하위 클래스는 implement 키워드를 이용한다.
interface RemoteControl { public abstract void turnOn(); public abstract void turnOff(); } class Rmc1 implements RemoteControl { public void turnOn() { System.out.println("Rmc1 리모컨이 켜집니다."); } public void turnOff() { System.out.println("Rmc2 리모컨이 꺼집니다."); } } class Rmc2 implements RemoteControl { public void turnOn() { System.out.println("Rmc2 리모컨이 켜집니다."); } public void turnOff() { System.out.println("Rmc2 리모컨이 꺼집니다."); } } public class example11 { public static void main(String[] args) { RemoteControl r1 = new Rmc1(); RemoteControl r2 = new Rmc2(); r1.turnOn(); r2.turnOff(); } }
RemoteControl 이라는 인터페이스를 만들었다.
이렇게 되면 Rmc1 리모컨과 Rmc2 리모컨은 turnOn, turnOff 메서드를 사용하지 않으면 오류가 난다.
인터페이스는 연산자가 아니므로 메모리에 띄울 수 없다.
인터페이스와 추상 클래스의 차이
인터페이스와 추상 클래스는 유사한 점을 가지고 있다. 비슷한 문법을 가지고 있고, 구현이 되지 않는 메서드를 가지고 있다. 차이를 비교해보자
우선 첫번째 그림을 보자
자동차는 운송수단인가? yes . 비행기는 운송수단인가? yes , 기차는 운송수단인가? yes
이렇다면 자동차는 운송수단이라는 추상 클래스를 구체화한 객체이다.
이때는 상속을 사용한다.
TV는 리모컨인가? NO, 홈시어터는 리모컨인가? NO, 스피커는 리모컨인가 ? NO
각 객체는 리모컨과 상관없지만 동일한 on off 기능을 포함하고 싶을 때 인터페이스를 사용한다.
클래스들 사이에서 코드를 공유하고 싶다면 추상 클래스, 관련 없는 클래스들이 동일한 동작을 구현하기 위해선 인터페이스를 이용하자.
Share article