C#을 배우면서 캡슐화(Encapsulation) 라는 개념을 들어본 적이 있으신가요?
캡슐화는 객체 지향 프로그래밍(OOP)의 핵심 개념 중 하나로, 데이터를 보호하고 코드의 안정성을 높이는 중요한 기능입니다.
이 글에서는 캡슐화의 개념, public, private, protected 접근 제한자의 차이를 쉽고 자세한 예제와 함께 설명해 드릴게요! 😊
🔹 캡슐화(Encapsulation)란?
💡 캡슐화(Encapsulation) 는 클래스 내부의 데이터(변수)를 외부에서 직접 접근하지 못하게 보호하는 것입니다.
📌 캡슐화의 핵심 목표
✅ 외부에서 데이터(변수)를 직접 변경하지 못하도록 보호
✅ getter 및 setter 메서드를 제공하여 안전하게 데이터 조작 가능
✅ 코드 유지보수성을 높이고, 오류를 방지
📌 캡슐화 예제 (잘못된 코드 - 캡슐화 적용 전)
using System;
class BankAccount
{
public int balance; // 🔴 누구나 직접 접근 가능 (위험!)
public void Withdraw(int amount)
{
balance -= amount;
}
}
class Program
{
static void Main()
{
BankAccount account = new BankAccount();
account.balance = -1000; // ❌ 직접 접근 가능 (잘못된 값 입력 가능)
Console.WriteLine($"잔액: {account.balance}");
}
}
🔍 실행 결과 (잘못된 데이터 입력)
잔액: -1000
💡 문제점
- balance가 public으로 선언되어 누구나 직접 접근 가능
- 잘못된 값(예: -1000)을 입력해도 막을 방법이 없음
➡ 이제 캡슐화를 적용하여 해결해 보겠습니다!
🔹 private를 활용한 캡슐화 적용 ✅
변수를 private으로 선언하고, getter 및 setter 메서드를 사용하여 안전하게 접근하도록 변경
using System;
class BankAccount
{
private int balance; // 🔒 외부에서 직접 접근 불가능
// 생성자 (초기 잔액 설정)
public BankAccount(int initialBalance)
{
balance = initialBalance;
}
// 잔액 조회 (getter 역할)
public int GetBalance()
{
return balance;
}
// 출금 기능 (setter 역할)
public void Withdraw(int amount)
{
if (amount > 0 && balance >= amount)
{
balance -= amount;
Console.WriteLine($"{amount}원 출금 완료!");
}
else
{
Console.WriteLine("출금할 수 없습니다. 잔액 부족 또는 잘못된 금액!");
}
}
}
class Program
{
static void Main()
{
BankAccount account = new BankAccount(10000); // 초기 잔액 10,000원
Console.WriteLine($"현재 잔액: {account.GetBalance()}");
account.Withdraw(3000); // 3000원 출금
Console.WriteLine($"현재 잔액: {account.GetBalance()}");
account.Withdraw(8000); // ❌ 출금 실패 (잔액 부족)
}
}
🔍 실행 결과
현재 잔액: 10000
3000원 출금 완료!
현재 잔액: 7000
출금할 수 없습니다. 잔액 부족 또는 잘못된 금액!
💡 캡슐화 적용 후
✅ private 키워드를 사용하여 외부에서 balance에 직접 접근 불가능
✅ GetBalance(), Withdraw() 메서드를 제공하여 안전한 데이터 조작 가능
✅ 출금 시 잔액을 체크하여 잘못된 값을 방지
➡ 이제 접근 제한자(public, private, protected)의 차이를 알아볼까요?
🔹 접근 제한자(Access Modifiers) 정리 🔍
C#에서는 변수(필드)와 메서드에 대해 어디서 접근할 수 있는지 제한할 수 있습니다.
대표적인 접근 제한자는 다음과 같습니다.
접근 제한자 | 설명 | 사용 가능 범위 |
public | 어디서든 접근 가능 | 모든 클래스 |
private | 해당 클래스 내에서만 접근 가능 | 현재 클래스 내부 |
protected | 현재 클래스 & 상속받은 클래스에서만 접근 가능 | 현재 클래스 + 자식 클래스 |
internal | 같은 프로젝트(어셈블리) 내에서만 접근 가능 | 동일 프로젝트 내부 |
➡ 각 접근 제한자가 실제로 어떻게 동작하는지 예제와 함께 살펴볼게요!
🔹 public vs private 차이점 👀
📌 public 변수: 외부에서 직접 접근 가능 (⚠ 위험!)
class Person
{
public string name; // ✅ 누구나 접근 가능
}
class Program
{
static void Main()
{
Person p = new Person();
p.name = "지훈"; // 외부에서 직접 수정 가능
Console.WriteLine($"이름: {p.name}");
}
}
✅ 결과 → 이름: 지훈 (하지만, 외부에서 데이터가 쉽게 변경될 수 있음)
📌 private 변수: 외부에서 직접 접근 불가능 (✅ 안전!)
class Person
{
private string name; // 🔒 외부에서 접근 불가능
public void SetName(string newName)
{
name = newName; // 내부에서만 변경 가능
}
public string GetName()
{
return name;
}
}
class Program
{
static void Main()
{
Person p = new Person();
// p.name = "지훈"; // ❌ 오류 발생 (private 변수는 직접 접근 불가!)
p.SetName("지훈"); // setter 메서드를 통해 값 설정
Console.WriteLine($"이름: {p.GetName()}");
}
}
✅ 결과 → 이름: 지훈 (외부에서 name을 직접 변경할 수 없도록 보호됨!)
🔹 protected (상속 관계에서 사용)
💡 protected 키워드는 현재 클래스와 상속받은 자식 클래스에서만 접근 가능합니다.
class Animal
{
protected string name; // 자식 클래스에서 접근 가능
public void SetName(string newName)
{
name = newName;
}
}
class Dog : Animal
{
public void Bark()
{
Console.WriteLine($"{name}가 멍멍 짖습니다!");
}
}
class Program
{
static void Main()
{
Dog myDog = new Dog();
myDog.SetName("바둑이"); // 부모 클래스의 public 메서드를 통해 설정
myDog.Bark();
}
}
✅ 결과 → 바둑이가 멍멍 짖습니다!
💡 protected 덕분에 자식 클래스인 Dog에서 부모 클래스 Animal의 name을 사용할 수 있어요!
🔹 정리
✅ 캡슐화(Encapsulation) → 데이터 보호 & 안전한 조작을 위한 객체지향 개념
✅ public → 어디서든 접근 가능 (⚠ 데이터 보호 X)
✅ private → 클래스 내부에서만 접근 가능 (✅ 안전한 데이터 보호)
✅ protected → 현재 클래스 + 상속받은 클래스에서 접근 가능
💡 캡슐화와 접근 제한자는 C# 객체지향 프로그래밍의 필수 개념입니다!
궁금한 점이 있으면 댓글로 질문 주세요! 😊