티스토리 뷰

IT/OOP

추상화(Abstraction) - 복잡함을 감추고 본질만 드러내는 설계의 미학

Stv 2025. 4. 16. 21:31

목차


    1. 추상화란?

    추상화(Abstraction)는 불필요한 구현 세부사항은 감추고, 핵심적인 개념이나 행위만을 정의하여 표현하는 객체지향 설계 원칙이다.
    즉, "무엇을 할 수 있는가"에 집중하고, "어떻게 구현할 것인가"는 감춘다는 철학

     

    📌Java에서의 예시

    • List 인터페이스만 알아도 ArrayList나 LinkedList의 구체 구현을 몰라도 사용 할 수 있음
    • 이처럼 추상화를 통해 사용과 구현을 분리하고, 유연한 설계를 할 수 있다.

     

    📌 예시로 이해하기

    • "TV 리모컨"은 전원을 켜고 채널을 바꿀 수 있음 (기능 = 추상화된 인터페이스)
    • 내부적으로 무슨 회로로 동작하는지는 알 필요 없음 (구현 = 캡슐화)
    public interface RemoteControl {
        void powerOn();
        void changeChannel(int channel);
    }
    • SamsungTV, LGTV는 이 인터페이스를 각자 다르게 구현 가능 (다형성 기반)

    2. 추상 클래스 vs 인터페이스

    항목 추상 클래스 인터페이스
    키워드 abstract class interface
    목적 공통 로직 + 확장 포인트 제공 기능 명세만 제공
    다중 상속 ❌ (단일 상속만 가능) ✅ (여러 인터페이스 구현 가능)
    접근제어자 필드, 생성자, protected등 가능 public static final, public abstarct가 기본
    사용 예 상위 클래스에 기본 동작을 제공하고 싶을 때 설계 중심 역할 분리, 전략/역할 분할 등

     

    📍 추상 클래스 예제

    public abstract class Animal {
        public void eat() {
            System.out.println("먹는다");
        }
    
        public abstract void sound(); // 구현은 하위 클래스에서
    }
    public class Dog extends Animal {
        @Override
        public void sound() {
            System.out.println("멍멍");
        }
    }

     

    📍 인터페이스 예제

    public interface Payment {
        void pay(int amount);
    }
    public class CreditCardPayment implements Payment {
        public void pay(int amount) {
            System.out.println("카드로 " + amount + "원 결제합니다");
        }
    }

     

    3. 실무에서 추상화가 중요한 이유

    ✅ 변경에 강한 설계

    • 구체 구현이 바뀌더라도 추상 타입(인터페이스, 추상 클래스)은 그대로 -> 클라이언트 코드 영향 없음

    ✅ 테스트와 유연성

    • 인터페이스 기반 -> Mock 객체 주입 가능 -> 테스트 용이

    ✅ 레이어 분리 & 아키텍처 기반 설계

    • Controller -> Service -> Repository 구조에서, Repository는 보통 인터페이스로 추상화
    • 구현체는 JDBC, JPA, MyBatis등 자유롭게 변경 가능
    public interface UserRepository {
        Optional<User> findById(Long id);
    }

     

    4. 추상화가 부족한 나쁜 설계 예시

    public class OrderService {
        private KakaoPayService kakaoPayService;
    
        public void pay() {
            kakaoPayService.requestPayment();
        }
    }
    • KakaoParService에 직접 의존
    • TossPayService, CardPayService를 쓰려면 기존 코드 수정 필요

    ✅ 개선 후

    public interface PaymentStrategy {
        void requestPayment();
    }
    
    public class OrderService {
        private final PaymentStrategy strategy;
    
        public OrderService(PaymentStrategy strategy) {
            this.strategy = strategy;
        }
    
        public void pay() {
            strategy.requestPayment();
        }
    }
    • 추상화가 안되어 있으면 구체 클래스에 직접 의존하게 되어, 새로운 요구사항이 생길 때마다 기존 코드를 수정해야 한다.
    • 이는 변경에 취약한 구조가 되고, 서비스 로직과 인프라 로직이 뒤섞여 테스트도 어렵고 재사용도 힘들어 진다.

     

    5. 실무에서 추상화가 자주 등장하는 예

    분야 추상화 대상 설명
    Spring Data JPA JpaRepository<T, ID> 구현체 없어도 기본 메서드 제공
    DI/IoC 인터페이스 기반 주입 구현 클래스는 외부에서 결정
    전략 패턴 Strategy 인터페이스 정책을 런타임에 교체 가능
    서비스 계층 분리 Service 인터페이스 테스트, 모듈화에 유리

     

    ✅ 마무리 요약

    • 추상화는 불필요한 정보는 숨기고 핵심 인터페이스만 제공하는 객체지향의 핵심 원칙
    • 추상 클래스는 공통 구현 포함, 인터페이스는 역할 분리와 유연성 확보에 강점
    • 실무에서는 역할 기반 설계, DI 컨테이너 기반 설계, 테스트 전략에 필수
    • 추상화가 잘 된 구조는 변경에 강하고, 테스트가 쉬우며, 유지보수성이 높다

    🔜 다음 포스팅 주제는 "SRP - 단일 책임 원칙 : 클래스는 하나의 책임만 가져야 한다" 주제로 포스팅 해보려고 한다. 객체 지향의 설계 원칙과 SOLID의 각 특성들은 연결되는 내용들이 많기 때문에 각 요소마다 이해를 하기보다는 전체적으로 연결지으며 이해하고 내것으로 만드는 것이 좋다.