Files
2nd/10_Wiki/Topics/Architecture/Extract Class (클래스 추출하기).md
T

5.2 KiB

Extract Class (클래스 추출하기)

📌 Brief Summary

'Extract Class(클래스 추출하기)'는 두 개의 클래스가 나누어 맡아야 할 역할을 하나의 클래스가 과도하게 수행하고 있을 때, 새로운 클래스를 생성하여 기존 클래스의 관련 필드와 메서드를 새 클래스로 이동시키는 리팩토링 기법이다 [1]. 소프트웨어가 진화함에 따라 단일 클래스에 책임과 데이터가 무분별하게 추가되어 비대해지고 복잡해지는 문제를 해결하기 위해 사용된다 [1]. 이 기법을 통해 클래스의 역할을 명확히 분담하고 응집도를 높임으로써, 시스템의 유연성과 유지보수성을 크게 향상시킬 수 있다 [2, 3].

📖 Core Content

적용해야 하는 주요 코드 스멜(Code Smells)

  • 거대 클래스(Large Class): 클래스가 너무 많은 인스턴스 변수와 코드를 가지고 있어 비대해졌을 때, 관련된 변수와 메서드를 묶어 새로운 클래스로 추출하여 역할을 분담한다 [3, 4].
  • 데이터 뭉치(Data Clumps): 여러 메서드나 클래스에 걸쳐 함께 몰려다니는 데이터 그룹이 있다면, 이를 독립된 클래스 객체로 추출하여 데이터 중복을 제거한다 [5, 6].
  • 뒤엉킨 변경(Divergent Change): 하나의 클래스가 여러 가지 다른 원인과 목적에 의해 잦은 수정이 일어나는 경우, 특정 변경 원인에 해당하는 데이터와 메서드들을 분리하여 새 클래스로 추출한다 [7].
  • 임시 필드(Temporary Field) 및 부적절한 친밀함(Inappropriate Intimacy): 특정 상황에서만 할당되는 고아 변수들을 모아둘 새로운 클래스를 만들거나 [8], 두 클래스 간의 공유 관심사를 안전하게 추출하여 결합도를 낮추는 데 활용된다 [9].

추출 기준 및 징후

  • 클래스 내 데이터의 특정 부분집합과 메서드의 특정 부분집합이 논리적으로 밀접하게 어울리는 경우 좋은 추출의 징후가 된다 [10].
  • 데이터의 특정 부분이 주로 함께 변경되거나, 특정 데이터들 사이에 강한 의존성이 있을 때 분리하는 것이 적절하다 [10]. 특정 데이터나 메서드를 제거했을 때 다른 필드와 메서드들이 논리적으로 의미를 잃는다면 이들을 하나의 클래스로 추출해야 한다 [10].

클래스 추출 절차 (Mechanics)

  1. 클래스의 책임을 어떻게 분할할지 결정하고, 분리될 책임을 표현할 새로운 클래스를 생성한다 [11].
  2. 기존 클래스에서 새로운 클래스로의 링크(참조)를 생성한다 [11].
  3. '필드 옮기기(Move Field)'와 '메서드 옮기기(Move Method)'를 차례로 사용하여 기존 클래스의 데이터와 기능을 새 클래스로 이동시킨다 [12, 13].
  4. 각 이동 과정마다 컴파일과 테스트를 반복하여 시스템의 동작이 보존되는지 확인한다 [13].
  5. 각 클래스의 인터페이스를 검토하여 불필요한 부분을 줄이고, 새 클래스를 클라이언트에게 노출할지 여부를 결정한다 [13].

⚖️ Trade-offs & Caveats

위임(Delegation)과 상속(Inheritance)의 선택 교환 '클래스 추출하기(Extract Class)'와 '서브클래스 추출하기(Extract Subclass)'는 객체의 책임을 분리할 때 마주하는 위임과 상속 사이의 선택이다 [14]. 서브클래스 추출이 구현하기는 더 간단하지만, 객체가 생성된 이후에는 클래스 기반의 동작을 동적으로 변경할 수 없으며 하나의 변화 축(variation)만 표현할 수 있다는 제약이 있다 [14]. 반면, 클래스 추출하기(위임)를 사용하면 런타임에 다른 컴포넌트를 끼워 넣는 방식으로 동작을 유연하게 변경할 수 있는 이점이 있다 [14].

에일리어싱(Aliasing)의 위험성 추출된 새로운 클래스를 클라이언트에게 직접 노출(expose)하기로 결정했다면 에일리어싱의 위험을 신중하게 고려해야 한다 [15]. 클라이언트가 참조를 통해 새로운 클래스 객체의 내부 상태(예: 전화번호 객체의 지역 번호 등)를 직접 변경할 경우, 이 객체를 참조하고 있는 다른 곳에서 예기치 않은 부수 효과가 발생할 수 있다 [15].

클래스 인라인하기(Inline Class)의 필요성 클래스 추출 및 기타 리팩토링의 결과로 기존 클래스에 남은 책임과 역할이 너무 적어져서 클래스로서의 존재 가치(비용 대비 효용)를 상실할 수 있다 [3, 16]. 이러한 경우, 최적화를 위해 반대 기법인 '클래스 인라인하기'를 사용하여 남은 기능들을 다른 클래스로 다시 병합하고 빈 클래스를 삭제해야 하는 반대 급부가 발생할 수 있다 [16].

인터페이스 추출의 코드 중복 완화 '인터페이스 추출하기(Extract Interface)'를 적용할 때 발생할 수 있는 코드 중복 문제를 완화하기 위한 수단으로 클래스 추출하기가 사용된다 [17]. 공통된 동작을 클래스로 추출하여 하나의 컴포넌트로 만들고 이를 인터페이스 구현체들이 위임받아 사용하게 하면 코드 중복을 피할 수 있다 [17].


Last updated: 2026-05-03