추상 클래스를 구현하면 겪었던 문제들

byeol·2023년 7월 14일

abstract method는 간단하게 설명하면 선언부는 있는데 구현부가 없는 메서드를 말합니다.

abstract class는 abstract method가 하나라도 있다면 abstract method가 되며 abstract method가 하나도 없어도 abstract class도 설정할 수 있습니다.

인터페이스 vs. abstract class 어떤 것을 선택해야 할까요?

중요한 것은 제가 면접을 준비하면 abstract class와 인터페이스의 차이점을 알고 있었지만

이를 적용해 본 적이 없어서 이번 "spring boot basic" 미션에서

인터페이스를 사용해야 하는지 abstract class를 사용해야 하는지에 대해서 갈피를 잡지 못했다는 것입니다.

상황은 이러합니다.

바우처 정책은 "고정된 금액을 할인해 주는 정책""할인율에 따라 할인해 주는 정책"이 있습니다.

이 두 정책의 공통된 기능은 할인을 해주는 것입니다.

그렇다면 당신이라면 인터페이스로 구현할 것인가요?

아니면 abstract class로 구현할 것인가요?

아니면 추상을 뻰 일반 클래스로 구현할 것인가요?

일단 인터페이스부터 생각해보면

바우처 정책 모두에 적용되는 공통된 기능이라는 점에서 인터페이스는 탈락입니다.

인터페이스를 공통된 기능이 아니라 기능의 확장 면에서 접근해야 하기 때문입니다.

만약에 몇 개의 정책에서 "무언가 할 수 있는" 기능이 있다면 인터페이스를 선택해야 합니다.

그 다음으로 추상 클래스와 추상을 뺀 상위 클래스에 대해서 생각해 봅시다.

할인을 해줍니다.

근데 할인을 해주는 것에 대해서 어떻게 정의해야 할까요?

그건 알 수 없습니다.

어떤 정책은 고정 금액으로, 어떤 정책은 할인율이기 때문에

상위 클래스에서 할인하다()에 대해서

정의를 내릴 수 없습니다.

기능에 대해서 정의를 할 수는 없지만 분명 모든 바우처 정책에서의 공통된 기능입니다.

따라서 abstract class의 abstract method를 선택하는 것이 적절해 보입니다.

즉 정리하면

바우처는 어떻게 할인해야 하지?

누가 실수로 바우처 객체를 만들면 어떡하지?

하지만 바우처 참조 변수 배열로 바우처의 할인을 적용한다면 하위 클래스에서 오버라이딩 해서 할인하다() 메서드가 바우처에 필요한데?...

그리고 오버라이딩 하지 않으면 컴파일시 에러가 발생하도록 강제성이 필요한데?

이런 상황에서 추상 클래스를 사용합니다.

추상클래스는 객체를 생성할 수 없으니 생성자도 없다?!

제가 가졌던 오해입니다.

추상클래스도 클래스이기 때문에 생성자가 있습니다.

그래서 저는 생성자를 만들어 놓지 않았고

그래서 계속 NPE가 발생해서 오랜 시간 이 문제를 해결하기 위해 고민했습니다.

모두들 자식 클래스 객체 생성시 부모 클래스의 생성자 호출 방식을 알고 계시나요?

자식 클래스가 객체를 생성할 때 이는 자식 클래스의 객체 생성만 발생하는 것이 아니라

최상위 클래스 생성자부터 아래로 내려오면서 타고타고 생성자를 만들면서 자식 클래스의 객체를 생성합니다.

이 때 자식 클래스가 부모 클래스의 어떤 생성자를 선택할까요?

그건 기본 생성자를 만들면서 내려옵니다. 하지만 이건 default이고 특정 생성자를 지정해 줄 수도 있습니다. 부모 클래스의 특정 생성자를 지정해주지 않는다면 기본 생성자를 만든다는 것입니다.

여기서 기본 생성자에 대해서 모르는 시는 분 있을까요?

자바의 모든 클래스에는 하나 이상의 생성자가 정의되어 있어야 합니다. 하지만 특별히 생성자를 정의하지 않고도 인스턴스를 생성할 수 있는데, 자바 컴파일러가 기본 생성자를 기본적으로 제공해 주기 때문입니다.

기본 생성자는 매개변수를 하나도 가지지 않고, 아무런 명령어도 포함되어 있지 않습니다. 자바 컴파일러는 컴파일 시 클래스에 생성자가 하나도 정의되어 있지 않다면 자동으로 만들어줍니다. 하지만 만약 매개변수를 가지는 생성자를 하나라도 정의했다면, 기본 생성자는 자동으로 추가되지 않는점을 유의해야 합니다.

즉 정리하면

자식 클래스의 생성자는 부모 클래스의 생성자를 호출합니다.

  • 만약에 자식 클래스의 생성자에 부모 클래스의 생성자를 호출하지 않았다면 기본적으로 부모 클래스의 기본 생성자를 호출합니다. 따라서 부모 클래스에 매개변수를 가지는 생성자가 하나라도 정의되어 있고 기본생성자가 정의되어 있지 않다면 기본 생성자를 정의해줘야 합니다.
  • 만약에 자식 클래스의 생성자에서 부모 클래스의 생성자를 호출한다면 순서가 중요합니다. 앞서 말했듯이 부모 클래스의 생성자를 먼저 호출해야하기 때문에 무조건 super 생성자가 먼저 등장해야 합니다.

profile
꾸준하게 Ready, Set, Go!

0개의 댓글