추상클래스에 대해서 생각해보자. 예를 들어 백엔드 개발자, 프론트엔드 개발자는 모두 develop()이라는 동작이 필요하다. 이 공통 동작을 조상 클래스 Developer에 선언하고, 각 자손 클래스가 자기 방식대로 override 하도록 만들고 싶다.
그런데, 여기서 문제가 생긴다.
예시)
abstract class Developer {
protected String name;
protected int years;
public Developer(String name, int years) {
this.name = name;
this.years = years;
}
// 공통 동작(재사용 가능)
public void attendStandup() {
System.out.println(name + " : 데일리 스탠드업 참여");
}
public void reviewCode() {
System.out.println(name + " : 코드 리뷰 진행");
}
// 자식 클래스가 반드시 구현해야 하는 핵심 동작
public abstract void develop();
}
class BackendDeveloper extends Developer {
public BackendDeveloper(String name, int years) {
super(name, years);
}
@Override
public void develop() {
System.out.println(name + " : API 개발 / DB 설계");
}
}
class FrontendDeveloper extends Developer {
public FrontendDeveloper(String name, int years) {
super(name, years);
}
@Override
public void develop() {
System.out.println(name + " : UI 구현 / 상태 관리");
}
}
abstract class는 상속 전용 클래스로 사용된다. 따라서 추상 메서드(구현부가 없는 메스드)가 존재할 수 있으므로, 객체 생성이 불가능하다.
대신, 상위 클래스 타입으로 자식 객체를 참조 가능
Developer dev = new BackendDeveloper("Yonu", 2); // O
dev.develop(); // BackendDeveloper의 develop() 실행
*** 자식 클래스가 상속받은 추상 메서드를 재정의 하지 않으면 그 자식 클래스도 추상 클래스가 되어야함
abstract class LazyDeveloper extends Developer {
public LazyDeveloper(String name, int years) {
super(name, years);
}
// develop()을 구현하지 않았으므로 추상 클래스여야 함
}
(1) 공통 설계 강제
하위 클래스가 반드시 구현해야 하는 메서드를 추상 메서드로 제공하여 구현을 강제한다.
(2) 코드 재사용성 향상
공통 필드/공통 메서드를 상위 클래스에 두고 하위 클래스가 재사용할 수 있다.
(3) 일관성 유지
같은 이름/형태의 메서드를 반드시 갖도록 하여, 하위 클래스들이 동일한 규격으로 동작하게 만든다.
(4) 다형성 지원
상위 타입으로 묶어 처리할 수 있어 유연한 설계가 가능하다.
| 구분 | 클래스 | 추상 클래스 |
|---|---|---|
| 정의 | 구체적인 객체(인스턴스)를 생성할 수 있는 클래스 | 추상 메서드를 포함할 수 있는 클래스 객체(인스턴스) 생성이 불가능한 클래스 추상적 개념의 구체적인 객체 생성이 논리적으로 맞지 않는 클래스, 객체 생성이 필요 없는 클래스 |
| 객체 생성 | 가능 | 불가 |
| 추상 메서드 | 포함 불가 | 추상 메서드를 포함할 수 있음 (추상 메서드 없어도 추상 클래스 생성 가능 - 객체 생성을 못하도록 강제) |
| 상속 | 다른 클래스에 의해 상속될 수 있음 | 다른 클래스에 의해 상속되면 추상 메서드가 구현되어야만 객체 생성 가능(세부 구현 강제) 만약 하위 클래스가 추상 메서드를 모두 구현하지 않으면 하위 클래스도 추상 클래스 |
| 키워드 | class 키워드 사용 | abstract class 키워드 사용 |
| 목적 | 완전한 클래스를 정의하여, 해당 클래스로 객체를 생성하기 위함 | 객체 생성 방지, 공통된 기본 기능을 정의(코드 중복 제거), 하위 클래스에서 세부 구현을 강제 |
| 타입 | 타입으로 사용 가능 | 타입으로 사용 가능 |