티스토리 뷰

IT/OOP

🔒 캡슐화(Encapsulation) - 객체지향의 시작점, 복잡성의 종착역

Stv 2025. 4. 14. 20:27

목차


    1. 캡슐화란?

    "캡슐화(Encapsulation)는 객체의 내부 구현을 숨기고, 외부에서는 정해진 방법(인터페이스)으로만 접근하게 하는 원칙"이다.
    • 즉, "데이터 + 행위"를 하나의 단위로 묶고, 외부에서 그 데이터에 직접 접근하지 못하도록 막는 것이 핵심이다.

    2. 왜 캡슐화가 중요한가?

     

    🎯 복잡성 감춤 (Information Hiding)

    • 내부 로직이 바뀌어도 외부 인터페이스는 그대로 -> 변경에 강한 구조
    • 사용자는 "무엇을 한다"만 알고 "어떻게"는 몰라도 됨을 의미

    🎯 무결성 보장

    • 객체 상태를 외부에서 직접 조작하지 못하게 하여 비정상 상태 방지

    🎯 테스트/디버깅/유지보수 용이

    • 코드가 어디에서 어떻게 바뀌는지 예측 가능

    3. 접근 제어자와 캡슐화

    : 캡슐화는 대부분 접근 제어자(Access Modifier)를 통해 구현된다.

     

    제어자 설명 사용 예
    private 클래스 내부에서만 접근 필드, 내부 메서드
    protected 같은 패키지 + 하위 클래스 상속 관계에서 사용
    public 어디서든 접근 가능 외부에서 호출 가능한 API
    (default) 같은 패키지 내에서만 내부 유틸 클래스 등

     

    📌 대표적인 캡슐화 예 : 필드 은닉

    public class Member {
        private String name; // 외부에서 직접 접근 불가
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            if (name == null || name.isBlank()) {
                throw new IllegalArgumentException("이름은 필수입니다.");
            }
            this.name = name;
        }
    }
    이렇게 하면, 외부에서 무분별하게 member.name = null 같은 접근을 막을 수 있음

     

    4. 캡슐화가 적용되지 않은 나쁜 코드 예시

    public class BankAccount {
        public int balance; // 필드가 public!
    
        public void deposit(int amount) {
            balance += amount;
        }
    }
    // 외부 코드에서 마음대로 조작 가능
    BankAccount account = new BankAccount();
    account.balance = -999999; // 무결성 파괴!

     

    5. 캡슐화가 잘 된 코드 구조

    public class BankAccount {
        private int balance;
    
        public int getBalance() {
            return balance;
        }
    
        public void deposit(int amount) {
            if (amount <= 0) throw new IllegalArgumentException("입금액은 0보다 커야 합니다.");
            balance += amount;
        }
    
        public void withdraw(int amount) {
            if (amount > balance) throw new IllegalArgumentException("잔액 부족");
            balance -= amount;
        }
    }
    외부에서는 balance에 직접 접근하지 못하고, 반드시 deposit과 whitdraw를 통해서만 조작 가능 -> 캡슐화 -> 유효성 검사로 안정성 확보

     

    🤔 자주 나오는 오해

    ❌ 무조건 Getter/Setter 쓰는 게 캡슐화다?

    결론부터 이야기 하면 아니다.
    캡슐화는 "외부로부터 내부 상태 보호 + 유효성 보장 + 인터페이스 제공"이 핵심이다.
    Getter/Setter는 캡슐화 수단일 뿐, 무분별한 Getter/Setter는 오히래 캡슐화 파괴이다.
    // 잘못된 예시
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
    // → 그냥 외부가 다 가져가고 바꿀 수 있다면? 캡슐화 의미 없음

     

    6. 실무 적용 포인트

    • DTO, Entity, VO 객체의 필드에는 무조건 private 사용
    • 비즈니스 로직이 포함된 객체라면 Setter는 꼭 유효성 검사를 포함시켜야 함
    • 객체 생성은 생성자(factory method)로 책임을 위임하여 불완전한 객체 생성을 막음

    ✅ 마무리 요약

    • 캡슐화는 "정보 은닉" + "상태 보호" + "인터페이스 제공"을 통해 객체의 안정성을 확보한다.
    • 접근 제어자를 적절히 사용하고, 유효성 검증이 포함된 메서드를 통해 상태를 조작하는 것이 핵심이다.
    • 무조건적인 Getter/Setter 남발은 캡슐화를 깨트릴 수 있다.
    • 실무에서도 캡슐화는 유지보수성과 안정성, 테스트 용이성에 직결되는 중요한 원칙이다.

    🔜 다음 포스팅에서는 OOP의 상속(Inheritance)에 대해서 다뤄볼 예정이다.