|

캡슐화는 getter를 숨기는 기술일까

캡슐화의 진짜 의미를 설명하는 대표 이미지
캡슐화의 핵심은 필드를 가리는 일이 아니라 상태와 규칙을 같이 지키는 데 있다

캡슐화는 getter를 숨기는 기술일까라는 질문은 OOP를 처음 배울 때 거의 반드시 지나갑니다. 많은 설명이 private 필드, getter, setter 규칙으로 시작하다 보니 캡슐화가 마치 “필드 노출 금지 규칙”처럼 느껴지기 쉽기 때문입니다.

하지만 실무에서 중요한 캡슐화는 조금 다릅니다. 핵심은 객체가 자기 상태를 어떤 규칙 아래에서 바꾸게 할 것인가에 더 가깝습니다.

이 글은 교과서 정의를 길게 반복하기보다, 실무에서 왜 캡슐화가 상태 보호 문제로 느껴지는지 쪽에 집중합니다. 즉 getter/setter 규칙보다 무결성을 누가 지키는지에 초점을 둡니다.


왜 getter/setter 이야기로 오해되기 쉬울까

캡슐화 입문 설명은 보통 필드를 private으로 두고 getter/setter를 만드는 코드부터 시작합니다. 그래서 사람들은 “밖에서 직접 접근 못 하게 하면 캡슐화구나” 정도로 받아들이기 쉽습니다.

하지만 setter가 아무 검증 없이 모든 상태 변경을 열어두고 있다면, 필드를 private으로 감쌌더라도 실제 보호 효과는 약할 수 있습니다.


캡슐화의 핵심은 상태와 규칙을 같이 두는 것

class BankAccount {
    private int balance;

    public void deposit(int amount) {
        if (amount <= 0) throw new IllegalArgumentException();
        balance += amount;
    }

    public void withdraw(int amount) {
        if (amount <= 0) throw new IllegalArgumentException();
        if (balance < amount) throw new IllegalStateException();
        balance -= amount;
    }

    public int getBalance() {
        return balance;
    }
}

이 객체가 더 캡슐화되어 보이는 이유는 getter가 있어서가 아니라, balance를 바꾸는 규칙이 객체 안에 있기 때문입니다. 즉 아무 코드나 마음대로 음수 출금을 만들 수 없습니다.


정보 은닉과 완전히 같은 말은 아니다

정보 은닉은 내부 구현 세부를 감추는 관점에 더 가깝고, 캡슐화는 그 감춤 위에 상태와 행위를 묶는 관점까지 포함해 이해하는 편이 실무에서는 더 도움이 됩니다.

즉 구현을 감춘다고 끝나는 것이 아니라, 감춘 상태를 어떤 규칙으로만 바꾸게 할지까지 함께 봐야 합니다.


getter가 있어도 캡슐화가 깨지지 않을 수 있다

캡슐화를 getter 금지 규칙처럼 보면 오해가 생깁니다. 읽기 전용 조회는 필요할 수 있습니다. 문제는 getter 자체보다, 상태 변경이 무방비하게 밖으로 새는가입니다.

  • 조회는 열어두되 변경은 규칙화할 수 있다
  • setter를 없애도 public mutable collection을 반환하면 보호가 약해질 수 있다
  • 결국 핵심은 상태 변경 경로를 누가 통제하느냐다

이 점은 빈혈 도메인 모델 글, 애그리거트 글과도 직접 이어집니다.


실무에서 보면 캡슐화는 이런 질문에 가깝다

  1. 이 상태를 아무 곳에서나 바꿔도 되는가
  2. 상태 변경 시 반드시 지켜야 할 규칙은 무엇인가
  3. 그 규칙의 주인은 정말 이 객체인가
  4. 조회와 변경을 같은 정도로 열어둘 필요가 있는가

이 질문을 던지면 캡슐화는 문법 규칙이 아니라 설계 질문처럼 보이기 시작합니다.


마무리

캡슐화는 getter를 숨기는 기술이라기보다, 객체가 자기 상태를 아무렇게나 바꾸지 못하게 하고 필요한 규칙 아래에서만 바꾸게 만드는 설계에 더 가깝습니다.

즉 중요한 것은 getter/setter 개수보다, 상태와 규칙이 정말 같이 보호되고 있는가를 보는 일입니다.

함께보면 좋은 글