본문 바로가기

Java

인터페이스 vs 추상 클래스

3주차 미션의 controller, service, 메뉴, 입출력부분을 구현하면서 느낀점은 반복적인 코드들이 많이 등장했다는 것이다.
1주차 피드백에 반복은 모든 악의 근원이라는 말이 있었기에, 공통적인 메소드를 엮어내기 위해 인터페이스와 추상클래스의 개념을 도입하기 위해 고민했었다. 하지만 조금 미숙한 부분이 있었기에 이렇게 정리해보려 한다.
이 역시 짧은시간 공부한 나의 알량한 지식으로 내린 결론이므로 이후 생각이 바뀔 수 있는 여지가 많다. 그냥 지금 저사람이 저런 생각을 가지고 있구나 라고 보면 되겠다.

 

 

 

1. 추상클래스

 

추상클래스는 아래의 형태로 만들 수 있다.

abstract public class Controller {
}

 

추상 클래스 내에서는

public abstract void A();

와 같은 형식으로 추상 메소드를 정의할 수 있다.(추상 메서드는 있어도 되고 없어도 된다.)

이렇게 추상 메소드로 정의한 메소드는 extends로 추상클래스를 상속받는 클래스에서 정의할 수 있다.(안해도됨)

 

또한 추상 클래스는 인스턴스 변수를 가질 수 있고, 생성자를 가질 수 있다.

추상클래스 자체는 객체의 생성이 불가능하지만, 

추상클래스 객체이름 = new 상속받은클래스(생성자 매개변수);

형태로 객체를 생성시킬 수 있다는 말이다.

물론 하위클래스에서 생성자를 아래처럼 정의해야 한다.

public StationController extends Controller{
  public Controller(int num) {
      super(num);
  }
}

 

 

또한 추상 클래스는 인터페이스와는 다르게(이말을 완전히 믿지는 마라. 뒤에 추가적인 내용이 나온다.)

완전한 구현이 된 메소드를 가질 수 있다. 상속받는 클래스들이 가질 수 있는 공통 메소드를 선언할 수 있다.

구현부를 가질 수 있다는 말이다. 따라서 상속받는 클래스들의 공통적인 메소드를 선언하여 중복문제를 해결할 수 있다.

 

 

추상 클래스의 목적은 부모와 자식관계에 있어서 상위 하위클래스를 나누고 상속을 통하여 기능을 확장하기 위함에 있다.

따라서 추상클래스의 상속(extends)는 다중상속을 지원하지 않는다.

(엄마가 여러명일 수 는 없지 않은가..?)

 

 

 

 

2. 인터페이스

 

인터페이스가 존재하는 목적은 하위 구현(implements) 클래스들의 뼈대를 만드는것이다.

행위의 틀  immutable 한 속성만으로 제한해서 유연성과 사용성을 극대화한것이 자바의 "interface이다"

인터페이스에 추상 클래스의 abstract 메소드와 같은 틀을 만들어놓고, 구현한 클래스에는 이 틀을 무조건 구현해야 한다.

 

인터페이스는 아래의 형태로 만들 수 있다.

interface Service {
}

 

인터페이스내의 필드는 public static final이 생략된 상수 필드를 사용한다. (생략 해야한다. 굳이 적으려했더니 빨간줄 뜨더라.)

이 상수필드는 구현한 모든 클래스에서 사용가능하다.

(공통적인 상수 필드를 위해 인터페이스를 구현하는 것은 인터페이스의 사용 목적에 맞지 않는 안티패턴이다.)

 

인터페이스 역시 객체생성이 불가능하다.

인터페이스는 추상 클래스와는 다르게 생성자를 가질 수 없다.

하지만 인터페이스를 구현한 클래스로 아래와 같은 형식으로 구현 클래스를 이용한 객체는 생성 가능하다.(다형성)

인터페이스명 객체명 = new 인터페이스를구현한클래스명();

 

또한 인터페이스는 다중구현이 가능하다.

 

추상클래스는 non-static 과 non-final 필드 및 public, private, protected 메소드를 사용 할 수 있다.
인터페이스는 public, static, final 을 상속할 수 있고 모든 상속 가능한 메소드는 public 이다. 

 

인터페이스는 위에서 말했듯이, 틀을 정의하는 것이다.

구현하는 메소드들은 인터페이스에 정의된 메소드들을 반드시 구현해야하고, 인터페이스에서는 무엇을 구현해야 하는지 구현부없이 '틀'만 제공하는 것이다.

 

이런 점에서 생긴 고민은

 

"나는 공통부분을 빼내고 싶은데, 각 클래스의 공통부분을 정의하고 구현하는 클래스들이 그 클래스를 구현하도록 하는것은 추상 클래스가 아닌 인터페이스로 하는것이 맞아 보인다.추상클래스는 계층적으로 깊게 내려갔을때 가독성의 문제도 떨어지고, super클래스에서 새로운 추상 클래스를 만들었다고 해도 하위 클래스에서는 알 수 없기도 하고.. 사용하려는 목적에 맞지 않아 보이는데 어떻게 하지.. "

 

였다.

 

 

이에 대한 답은, 위에서 믿지 마라한것처럼, Java 8버전에 인터페이스의 변경점을 이용하면 된다.

 

 

3. Java 8 Interface

자바 8에서는 인터페이스에 구현부를 넣을 수 있게 해줬다. has-a만 허용하던 인터페이스에서 추상클래스의 is-a 구현을 약간이나마 사용할 수 있게, defaul와 static을 지원한다. 이게 무슨 말이냐. 아래를 보자.

 

interface Controller {
	void method1(int a, String b...);
    
    default String method2(String c, String d) {
    	// 구현;
    }
}

이처럼 인터페이스에서도 구현부를 가질 수 있다.

이렇게 default키워드를 붙여서 말이다.

 

이 default가 붙은 메소드는 인터페이스를 구현한 모든 클래스의 객체가 사용할 수 있다.

또 @Override를 통해 구현한 클래스에서 재정의 할 수 있다. 

이는 인터페이스에서 원래 제공하던 추상메소드를 구현체에서 무조건 구현해야 하던 점과는 다르다. 하위 클래스에서 이 default메소드를 다시 구현해야 하는 것을 강제하지 않는다. 유연성이 조금 올랐다고 말할 수 있겠다.

이 default메소드로 공통부분을 해결 할 수 있다는 말이다.

 

 

 

 

static 메소드는 말 그대로 정적으로 메소드를 선언하는 것이다. 이 또한 구현부를 가질 수 있다.

interface Controller {
	void method1(int a, String b...);
    
    public static String method3(String c, String d) {
    	// 구현;
    }
}

이 메소드는 정적으로 메모리에 할당되기에, 하위 클래스에서 재정의할 수 없다.

그리고 Controller.method3() 처럼 호출하여 사용할 수 있다.

 

 

 

 

 

결론: 공통부분을 때어낼 때도 인터페이스를 사용할 수 있다. 아는것이 힘이다.

 

 

 

 

 

 

 

아래 블로그를 참고했습니다.. 이해안가시면 그냥 아래 블로그 글 봐주시면 될 것 같습니다..

글쓰는 재주가 없어서..

hamait.tistory.com/650

[Java 8] 인터페이스 vs 추상 클래스

인터페이스 vs 추상 클래스 예전에 이 캐캐묵은 논쟁에 대한 글을 쓴적이 있었는데 , 그 중 일부를 발췌해보면 " 먼저 왜 자바는 인터페이스를 만들게 됬나를 생각해야 하며 , 다중상속은 이 둘

hamait.tistory.com

 

'Java' 카테고리의 다른 글

Enum 활용(람다식 사용하기)  (0) 2020.12.18
함수형 인터페이스 정리  (0) 2020.12.18
JAVA8) 스트림 API  (0) 2020.12.11
JAVA8) 메소드 레퍼런스  (0) 2020.12.11
JAVA8) 람다 표현식  (0) 2020.12.11