OOP - Encapsulation(캡슐화)이란 무엇이며 왜 사용하는가?

 

캡슐화/정보은닉(인포메이션 하이딩)쉽게 풀어주기 부제: 자바에서 멤버변수는 다 프라이빗키워드로 설계하기를 권고하는 이유는?

부제: 자바에서 멤버변수는 왜 private으로 설계해야 할까?

마치 자원재활용시 공장에 보내는것과 같다

우린 공장안이 어떻게 돌아가는지 알고싶지않다

알고싶지도 않고 알필요도없는걸 알려줄필요는없고 보여줄이유도 없다


자바 공부를 하다 보면 멤버변수(필드)는 꼭 private으로 선언하고, 접근은 반드시 public 메소드(getter/setter)를 통해 하라는 규칙을 자주 듣는다.


그럼 왜 굳이 이렇게 번거롭게 설계하라고 하는 걸까? 

성능이 좋아지는 것도 아닌데, 왜 이 방식을 따르는 걸까? 

이번 글에서 인포메이션 하이딩(정보 은닉)과 캡슐화 개념을 쉽게 풀어서 정리해주겠다



ai에 물어보니 이렇게 설명해준다

{

캡슐화/정보은닉
캡슐화와 정보 은닉은 객체 지향 프로그래밍의 핵심 원칙으로, 서로 밀접하게 연관되어 있지만 엄연히 다른 개념입니다
. 
캡슐화 (Encapsulation)
캡슐화는 데이터(속성)와 데이터를 처리하는 기능(메서드)을 하나의 단위(객체)로 묶는 것을 의미합니다. 마치 알약이 여러 성분을 하나의 캡슐 안에 담는 것처럼, 관련된 변수와 메서드를 클래스 안에 함께 묶어 관리합니다. 
  • 목적: 관련 있는 정보들을 논리적으로 묶어 객체의 완성도를 높이고, 코드의 응집도를 향상시켜 재사용성과 유지보수성을 높입니다.
  • 예시자동차 클래스 안에 속도와 같은 데이터와 가속정지와 같은 메서드를 함께 묶는 것입니다. 
정보 은닉 (Information Hiding)
정보 은닉은 객체 내부의 구체적인 구현 내용을 외부에 숨기고, 외부에 노출된 인터페이스를 통해서만 접근을 허용하는 소프트웨어 설계 원칙입니다. 
  • 목적: 외부에서 객체 내부의 데이터를 직접 수정하는 것을 방지하여 데이터의 무결성을 보호하고, 내부 구현이 변경되어도 외부에 미치는 영향을 최소화하여 유연성을 확보합니다.
  • 구현: 대부분의 객체 지향 언어에서 private와 같은 접근 제어자를 사용하여 외부 접근을 제한함으로써 구현됩니다. 
캡슐화와 정보 은닉의 차이점
두 개념은 상호 보완적이지만, 다음과 같은 차이점이 있습니다. 
구분 캡슐화 (Encapsulation)정보 은닉 (Information Hiding)
개념데이터와 기능을 하나로 묶는 행위.객체의 내부 구현을 외부에 숨기는 원칙.
행위묶는다(Binding).숨긴다(Hiding).
목적데이터와 기능의 관련성을 높여 응집도를 높임.내부 구현을 외부에 노출하지 않아 유연성과 안정성을 높임.
관계캡슐화는 객체와 인터페이스를 정의하는 것이고, 정보 은닉은 캡슐화의 결과로 얻을 수 있는 이점입니다. 즉, 캡슐화는 정보 은닉을 가능하게 하는 기술적인 방법 중 하나입니다.
예시: 은행 계좌 클래스
BankAccount 클래스를 통해 두 개념을 이해할 수 있습니다.
Java 코드 예시
java
public class BankAccount {
    // 캡슐화: 'balance' 데이터와 이를 조작하는 'deposit', 'withdraw' 메서드를 묶음
    private double balance; // 정보 은닉: 'balance'를 private로 선언해 외부에서 직접 접근 불가

    public BankAccount(double initialBalance) {
        if (initialBalance > 0) {
            this.balance = initialBalance;
        } else {
            this.balance = 0;
        }
    }

    // public 메서드를 통해 간접적으로 접근 허용
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
    }

    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
        }
    }

    public double getBalance() {
        return balance;
    }
}
코드를 사용할 때는 주의가 필요합니다.
이 예시에서,
  • 캡슐화balancedeposit()withdraw()getBalance()가 BankAccount 클래스 안에 묶여 있습니다.
  • 정보 은닉balance 변수가 private로 선언되어 외부에서 직접 접근할 수 없으며, 반드시 deposit()이나 withdraw()와 같은 **공개된 메서드(인터페이스)**를 통해서만 조작할 수 있습니다. 만약 내부 구현에서 balance 변수명을 accountBalance로 바꾸더라도 외부 코드에는 영향을 미치지 않습니다. 

}



인포메이션 하이딩이란?

쉽게 말하면 집주소는 알려주되, 모든 문과 창문을 막아버리는 것이다.
외부에서 마음대로 드나들 수 없게 만들고, 대신 뒷문이나 지하 터널 같은 특별한 통로를 만들어서만 들어올 수 있게 하는 것.

이 특별한 통로가 바로 **public 메소드(getter, setter)**다.
외부에서 객체 안에 있는 데이터를 직접 건드릴 수 없게 막아두고, 대신 정해진 방법으로만 접근하게 설계하는 게 인포메이션 하이딩이다.


왜 이렇게 해야 할까?

많은 사람들이 처음에 묻는 질문이 있다.

  • "성능이 더 좋아지나요?"
    → 아니다. 성능은 오히려 약간 손해다. 변수에 바로 접근하는 게 더 빠르지만, 메소드를 한 번 거쳐야 하니까 호출 오버헤드가 생긴다.

  • "그럼 왜 굳이 이렇게 하는 거죠?"
    → 데이터의 무결성 때문이다.
    외부에서 마음대로 멤버변수 값을 바꿔버리면 엉뚱한 값이 들어갈 수 있고, 프로그램 전체가 꼬일 수 있다.
    그래서 중간에 검증 절차를 두는 것이다. setter 안에 유효성 검사 로직을 넣어서, 이상한 값은 아예 들어오지 못하게 막을 수 있다.


코드 예시

public class Person {
    // 멤버변수는 무조건 private
    private String name;
    private String addr;
    private int age;

    // setter: 외부에서 값을 넣어줄 때 사용
    public void setName(String name) {
        // this.name = name;   // this로 멤버변수와 매개변수를 구분
        this.name = name;
    }

    // getter: 외부에서 값을 가져올 때 사용
    public String getName() {
        return this.name;
    }
}

this 키워드의 의미

setter 안에서 매개변수와 멤버변수의 이름이 같을 때, 자바는 가까운 이름부터 인식한다.
즉, 아래처럼 쓰면 오른쪽 name도, 왼쪽 name도 둘 다 매개변수를 가리킨다.

name = name; // 의도와 다르게 동작!

그래서 this.name = name; 처럼 this 키워드를 붙여야 현재 객체의 멤버변수에 값을 넣는다는 의미가 된다.


getter/setter를 쓰는 이유 정리

  1. 데이터 은닉

    • 멤버변수를 private으로 막아서 외부에서 직접 접근 불가.

  2. 데이터 무결성 보장

    • setter 안에 검증 로직을 넣어 잘못된 값이 들어오지 못하게 제어 가능.

  3. 유연한 확장성

    • 나중에 멤버변수 구조가 바뀌어도, 메소드만 잘 유지하면 외부 코드는 크게 수정할 필요 없음.


직접 접근 vs 메소드 접근

// 직접 접근 (나쁜 예시)
p1.name = "홍길동";  

// getter/setter 사용 (권장 방식)
p1.setName("홍길동");
System.out.println(p1.getName());

둘 다 결과적으로 값이 저장되고 출력되지만,
첫 번째 방식은 데이터 검증이 불가능하다.
두 번째 방식은 메소드를 통해 중간 제어가 가능하므로 안전하다.


정리

  • 인포메이션 하이딩 = 멤버변수를 숨기고, 메소드로만 접근하게 만드는 것

  • 성능은 손해지만, 데이터 무결성과 보안성을 위해 꼭 필요한 개념

  • setter는 값을 저장, getter는 값을 꺼내오기 위한 통로

  • 스프링 같은 프레임워크도 이 규칙을 따르지 않으면 제대로 동작하지 않는다

즉, 멤버변수에 문을 달아놓는 대신 튼튼한 뒷문(getter/setter)을 만드는 게 핵심이다.


👉 이 글을 다 이해했다면, **"getter와 setter로 접근하는 것과 직접 변수에 접근하는 것의 차이를 설명해보라"**라는 질문에 자신 있게 대답할 수 있을 것이다.

자바 정보은닉 / 캡슐화 쉽게 이해하기

자바를 배우면 꼭 듣는 말이 있죠.
"멤버변수는 무조건 private, 접근은 getter/setter로!"

근데 왜 이렇게 번거롭게 해야 할까요?


집 비유로 설명하기

멤버변수를 집이라고 생각해봅시다.

  • 집주소(클래스)는 알려줬어요.

  • 근데 창문, 정문을 다 막아버렸습니다. (private 멤버변수)

  • 대신 지하터널이나 뒷문을 하나 만들어서만 들어올 수 있게 했습니다. (getter/setter)

이게 바로 **정보은닉(Information Hiding)**이에요.


왜 굳이 이렇게 하나?

  • 성능이 좋아지는 건 아님 ❌ (오히려 메소드 호출이라 조금 더 느림)

  • 대신 데이터 무결성을 지킬 수 있음 ⭕

예를 들어 나이(age)라는 멤버변수가 있다고 해봅시다.
만약 아무 제약 없이 외부에서 -10 같은 값을 넣어버리면 이상하죠?
하지만 setter 안에 **"0보다 작은 값은 안 받는다"**라는 검증 코드를 넣으면 안전해집니다.


코드 예시

public class Person {
    private int age;

    public void setAge(int age) {
        if(age < 0) {
            System.out.println("나이는 음수가 될 수 없습니다!");
            return;
        }
        this.age = age;
    }

    public int getAge() {
        return this.age;
    }
}

직접 접근 vs 메소드 접근

// 직접 접근 (문제 발생 가능)
p1.age = -10;

// setter 사용 (안전)
p1.setAge(-10); // "나이는 음수가 될 수 없습니다!" 출력

핵심 정리

  • private 변수 + public getter/setter = 정보은닉/캡슐화

  • 성능은 손해지만, 데이터의 안정성을 위해 필수

  • getter/setter는 단순히 값 주고받는 통로가 아니라, 데이터를 지키는 보안관 역할


👉 그래서 스프링 같은 프레임워크도 이 규칙을 강하게 권장합니다.


댓글

가장 많이 본 글