2025-09-08

1일 1아티클

LY

Child Lock

오버라이딩 시 발생할 수 있는 문제점 및 해결 방안

  • 오버라이딩 : 부모 클래스의 method를 자식 클래스가 재정의하는 것
  • 해결 방안 : 자식 클래스가 부모의 핵심 로직을 망가뜨리지 않도록, 꼭 필요한 부분만 변경하도록 최소한으로 열자.

문제 상황

  • 공통 작업 : 헤더와 푸터 업데이트
  • 개별 작업 : 메시지 목록 화면 표시 (자식 클래스가 구현해야 하는 부분)

// BEFORE: 문제가 있는 설계
abstract class MessageListPresenter<T> {
    // 헤더/푸터 업데이트와 목록 표시를 하나의 메서드에 담음
    open fun bind(messageList: List<T>) {
        updateHeader(messageList.size)
        updateFooter(messageList)
        // 목록 표시는 자식 클래스가 super.bind() 호출 후 직접 구현해야 함
    }
}

class SomeSpecificMessageListPresenter : MessageListPresenter<SomeData>() {
    override fun bind(messageList: List<SomeData>) {
        super.bind(messageList) // <-- 실수로 빼먹으면 큰일 남
        // ... 여기서 목록 표시 로직을 구현
    }
}

  1. super 호출 누락 : 자식 클래스에서 super.bind(messageList) 를 까먹고 미호출 시, 헤더&푸터 업데이트 불가능한 버그 발생. 특별한 에러 발생도 되지 않아 버그가 간과될 가능성 농후
  2. 오버라이딩 누락 : 위의 코드에서 “목록 표시 로직 구현” 규칙이 주석으로만 존재하여, 개발자가 오버라이딩 자체를 잊을 수 있음
  3. 의도와 다른 구현 : 자식 클래스는 목록 표시만 구현해야 하는데, bind method 전체가 열려있어 헤더/푸터 로직까지 건드리는 등 엉뚱한 결과 발생

해결 방안

  • Template Method Pattern 사용
  • 전체 로직의 뼈대는 부모 클래스가 가지며, 자식 클래스마다 달라져야 하는 부분만 추상 메서드로 정의하여 자식이 구현하도록 강제하는 방식

// AFTER: 템플릿 메서드 패턴을 적용한 개선된 설계
public abstract class MessageListPresenter<T extends MessageData> {

    // final 키워드로 자식이 오버라이딩하는 것을 막음 (Child Lock)
    public final void bind(List<T> messageList) {
        // 로직의 순서는 부모가 통제한다.
        this.updateHeader(messageList.size());
        this.updateFooter(messageList);
        this.updateMessageList(messageList); // 자식이 구현한 로직을 호출
    }

    // 자식은 이 부분만 '반드시' 구현해야 한다.
    protected abstract void updateMessageList(List<T> messageList);

    private void updateHeader(int messageCount) {
        // ... 헤더 업데이트 로직
    }
    private void updateFooter(List<T> messageList) {
        // ... 푸터 업데이트 로직
    }
}

public class SomeSpecificMessageListPresenter extends MessageListPresenter<SomeSpecificMessageData> {

    // 이제 updateMessageList만 구현하면 된다. super를 호출할 필요도 없고, 잊어버릴 수도 없다.
    @Override
    protected void updateMessageList(List<SomeSpecificMessageData> messageList) {
        // ... 오직 '메시지 목록 표시' 로직에만 집중
    }
}

오버라이딩 가능한 범위는 최대한 제한하여, 자식 클래스가 해야 할 일만 하도록 하고 실수의 여지를 주지 않는 것이 좋다.

오늘 배운 것

  1. 알고리즘
    • swea 3282 0/1 Knapsack
    • 냅색 알고리즘

내일 할 일

  1. 포트폴리오 내용 복기

참고자료

results matching ""

    No results matching ""