객체지향의 4대 특징을 정리하면서 추상화를 설명할 때 인터페이스를 예로 들어 설명을 했다. 공통적인 속성과 기능을 정의하기 위해 인터페이스를 사용한다라고 설명했다.
그럼 내가 알고 있는 인터페이스와의 개념과 사용용도를 생각해 보자.
인터페이스는 기술명세서 또는 다양한 구현체가 존재할 수 환경에서의 기초가 되는 틀정도 개념으로 사용하였다. 예를 들어 설명하자면 스프링 프로젝트에서 비즈니스 로직을 구현하는 Service단에서 기능 구현 전 인터페이스를 생성하여 기능의 명세만 먼저 작성하는 행위, DB가 정해지기 전 작업을 진행하기 위해 기준 Repository를 인터페이스 선언하여 구현하는 행위 등의 용도로 사용하였다.
이제 인터페이스의 특징과 기능을 정리해 보고 그것이 객체지향 관점에서 어떤 역할을 하는지 대해 작성해 보자.
인터페이스(Interface)
인터페이스는 일종의 추상클래스이다. 추상클래스와 다른 점이 있다면 더 높은 추상화 정도를 가지고 있어 일반 메서드와 멤버변수를 가질 수 없다는 점이다.
인터페이스의 특징
- 인터페이스는 상수와 메소드만을 구성 멤버로 가진다.
- 모든 메서드는 추상메서드로 선언된다.
- public abstract
- 모든 변수는 상수로 선언한다.
- public static abstract
- 인터페이스는 객체로 생성할 수 없기 때문에 생성자를 가질 수 없다.
- 자바 8 이후부터는 디폴드 메서드와 정적 메서드 기능을 제공하여 일부 구현이 가능하다.
public interface 인터페이스명 {
// 상수[public static final] 생략가능
타입 상수명 = 값;
// 추상 메소드 [public abstract] 생략가능
타입 메소드명(매개변수, ...);
// 디폴트 메소드
default 타입 메소드명(매개변수, ...) {
...
}
// 정적 메소드
static 타입 메소드명(매개변수, ...) {
...
}
}
인터페이스의 상속과 구현
인터페이스는 인터페이스로부터만 상속이 가능하다. 클래스와 달리 다중상속, 즉 여러 개의 인터페이스로부터 상속을 받는 것이 가능하다.
public interface X {
void x();
}
public interface Y {
void y();
}
// 인터페이스를 여러 개를 상속받을 수 있다.
public interface MyInterface extends X, Y {
void myMethod();
}
MyInterface 인터페이스는 X, Y 인터페이스를 상속받고, 본인의 추상메서드 myMethod()를 가지고 있다. 총 3가지의 메서드를 가지고 있다고 보면 된다. 여기서 알 수 있듯이 인터페이스가 여러 인터페이스를 상속받으면, 상속받은 인터페이스는 상위 인터페이스에 선언된 추상 메서드를 모두 가지게 된다.
인터페이스의 구현은 추상클래스처럼 그 자체로는 인스턴스를 생성할 수 없다. 인터페이스는 추상클래스와 마찬가지로 자신을 정의해 줄 클래스에 상속함으로 구현이 된다. 다만 클래스의 상속 키워드인 'extends' 대신 확장의 의미를 가진 'implements' 키워드를 사용한다.
그럼 위 코드를 기반으로 클래스를 이용한 인터페이스 구현을 해보자.
public class MyClass implements MyInterface {
// X 인터페이스에서 상속받은 x()메서드 구현
@Override
public void x() {
System.out.println("x()");
}
// Y 인터페이스에서 상속받은 y()메서드 구현
@Override
public void y(){
System.out.println("y()");
}
// MyInterface 인터페이의 myMethod() 메서드 구현
@Override
public void myMethod(){
System.out.println("y()");
}
}
MyInterface 인터페이스를 구현하는 MyClass 클래스이다. MyInterface 인터페이스는 myMethod() 메서드만이 선언되어 있지만 X,Y 인터페이스를 상속받음으로 MyClass에서는 모든 메서드를 구현해야 한다.
인터페이스의 형변환
인터페이스를 구현한 클래스는 인터페이스 타입으로 선언한 변수로 형변환하여 사용할 수 있다. 상속에서의 형 변환과 동일한 내용이며 형 변환되는 경우 인터페이스에 선언된 메서드만 사용이 가능하다.
위에서 작성한 'MyClass' 클래스를 기준하여 테스트 코드를 작성한 예제이다.
public class MyClassTest {
public static void main(String[] args) {
MyClass m = new MyClass();
// 상위 인터페이스 X 타입으로 대입하면 X에 선언된 메서드만 사용 가능하다.
X xClass = m;
xClass.x();
// 상위 인터페이스 Y 타입으로 대입하면 Y에 선언된 메서드만 사용 가능하다.
Y yClass = m;
yClass.y();
// 구현한 인터페이스 타입으로 대입하면 해당 인터페이스가 상속한 모든 메서드가 호출가능하다.
MyInterface i = m;
i.myMethod();
i.x();
i.y();
}
}
코드를 보면 알겠지만 인터페이스를 구현한 MyClass 클래스 객체는 상속된 인터페이스 타입으로 형변환이 가능하다. 다만 형변환을 하면 해당 인터페이스 타입에 선언된 메서드만을 호출하여 사용할 수 있다.
그럼 객체지향 관점에서 인터페이스의 역할은 무엇일까?
인터페이스를 객체지향의 관점에서 본다면 "객체의 공통적인 행위를 추출하는 추상적인 개념으로 설계되며 한 객체가 여러 형태를 가질 수 있는 다형성의 형태로 구현된다."로 정의 할 수 있을 것 같다.
스프링의 서비스 영역을 인터페이스로 정의하여 기능 명세서로 사용하였다고 언급했는데 이것은 기능에 대한 규약 또는 청사진형태로 표현하고 구체적인 구현을 하지 않는 메서드 시그니처로만 정의하는 행위는 결국 추상화라고 볼 수 있다.
또, DB가 정해지지 않았을 때 인터페이스를 기본 틀로 두고 구현하는 행위는 변경 DB에 따라 여러 형태를 가질 수 있는 다형성과 관련되어 있다고 볼 수 있다.
결론적으로 인터페이스는 객체지향의 특징 중 추상화와 다형성과 깊은 연관성을 가지고 있다.
정리를 마치며
객체지향은 개념적인 요소로만 접근했을 때는 정답을 확정해서 말하기 어려운 부분이 있다. 그만큼 다양한 관점을 가지고 있다. 이런 객체지향을 어느 정도 확정성 있는 요소로 접근하기 위해선 코드로 녹이는 작업을 많이 해보는 것이 필요하다. 앞으로 개인 프로젝트 또는 팀 프로젝트를 할 기회가 많이 남아있는데 이런 객체지향요소를 코드로 녹일 수 있는 연습을 의식적으로 해봐야겠다.
Reference
[자바의 정석]과 [Do it! 자바 프로그래밍 입문] 책을 참고하여 작성하였습니다.
'Language > Java' 카테고리의 다른 글
[스진초5기/Java] Overriding과 Overloading (0) | 2023.10.27 |
---|---|
[Java] String[]을 List , List를 String[]로 변환하는 방법 (0) | 2023.10.24 |
[스진초5기/Java] 오버라이딩을 구현할 때 꼭 @Override가 필요할까? [+어노테이션의 역할] (0) | 2023.10.23 |
[Java] 인터프리터와 컴파일러 그리고 Java (1) | 2023.10.23 |
[스진초5기/Java] 객체지향의 4가지 특징 (0) | 2023.10.19 |