추상 클래스
일부 구현은 제공하되, 일부는 하위 클래스에게 구현을 강제하는 미완성 클래스입니다.
핵심 개념
// 추상 클래스 = "공통 부분은 내가 구현, 나머지는 너가 구현해"
abstract class Animal {
protected String name; // 공통 필드
public Animal(String name) { // 생성자 가능
this.name = name;
}
// 공통 동작 → 직접 구현
public String getName() { return name; }
// 동물마다 다름 → 하위 클래스에 강제
public abstract void sound();
}
// X 직접 생성 불가
Animal a = new Animal("동물"); // 컴파일 에러
// O 상속받아 사용
class Dog extends Animal {
public Dog(String name) { super(name); }
@Override
public void sound() { System.out.println("멍멍"); }
}
특징
| 항목 | 내용 |
|---|---|
| 일반 메서드 | O 구현 가능 |
| 추상 메서드 | O 선언만 가능 (하위 클래스 구현 강제) |
| 필드 | O 자유롭게 선언 가능 |
| 생성자 | O 가능 (직접 인스턴스화는 불가) |
| 다중 상속 | X 단일 상속만 가능 |
추상 메서드가 없어도 추상 클래스 가능
// 추상 메서드 없이도 abstract 선언 가능
// → 인스턴스화만 막고 싶을 때 사용
abstract class BaseConfig {
protected String host = "localhost";
protected int port = 8080;
public String getAddress() {
return host + ":" + port;
}
// 추상 메서드 없음 → 그래도 직접 생성 불가
}
템플릿 메서드 패턴 - 핵심 활용법
추상 클래스의 가장 대표적인 활용 방식입니다.
abstract class DataProcessor {
// 전체 흐름은 고정 (템플릿)
public final void process() {
readData(); // 공통
processData(); // 각자 다르게
saveData(); // 공통
}
private void readData() { System.out.println("데이터 읽기"); }
private void saveData() { System.out.println("데이터 저장"); }
// 하위 클래스가 채워야 할 부분
protected abstract void processData();
}
class CSVProcessor extends DataProcessor {
@Override
protected void processData() { System.out.println("CSV 파싱"); }
}
class JSONProcessor extends DataProcessor {
@Override
protected void processData() { System.out.println("JSON 파싱"); }
}
// 실행
new CSVProcessor().process();
// 데이터 읽기 → CSV 파싱 → 데이터 저장
인터페이스와 선택 기준
공통 필드/구현을 공유해야 한다 → 추상 클래스
IS-A 관계다 (Dog is an Animal) → 추상 클래스
다중 상속이 필요하다 → 인터페이스
능력/기능을 명세하고 싶다 → 인터페이스
추상 클래스는 "공통된 뼈대는 내가 제공하고, 세부 구현은 너가 채워라" 는 구조입니다. 전체 흐름을 고정하고 일부만 확장 지점으로 열어두는 템플릿 메서드 패턴에서 가장 빛을 발합니다.