추상 클래스

일부 구현은 제공하되, 일부는 하위 클래스에게 구현을 강제하는 미완성 클래스입니다.

핵심 개념

// 추상 클래스 = "공통 부분은 내가 구현, 나머지는 너가 구현해"
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) → 추상 클래스
다중 상속이 필요하다            → 인터페이스
능력/기능을 명세하고 싶다       → 인터페이스

추상 클래스는 "공통된 뼈대는 내가 제공하고, 세부 구현은 너가 채워라" 는 구조입니다. 전체 흐름을 고정하고 일부만 확장 지점으로 열어두는 템플릿 메서드 패턴에서 가장 빛을 발합니다.

CSLOG에서 보기