CodeGym /행동 /C# SELF /캡슐화를 실전에 적용하기

캡슐화를 실전에 적용하기

C# SELF
레벨 17 , 레슨 4
사용 가능

1. 접근을 컨트롤하자

캡슐화는 모든 걸 숨기는 게 아니라 컨트롤된 접근을 제공하는 것이야.

초보자들은 캡슐화가 그냥 모든 필드를 private로 만드는 거라고 생각하곤 해. 물론 필드는 보통 private로 하지만, 그게 전부는 아니야. 핵심은 데이터를 숨기는 것이 아니라, 접근을 관리하는 것이야.

가끔은 완전히 변경을 막아야 할 때도 있고(예: get-only 프로퍼티), 가끔은 읽기/쓰기를 허용하되 검증이 필요할 때도 있어. 또 어떤 때는 클래스 내부에서만 읽고 쓸 수 있게(public Type Property { get; private set; }) 할 수도 있지.

캡슐화를 통해서 객체에 대한 "게임의 규칙"을 만들 수 있어: 어떻게 바꿀 수 있는지 정하고, 항상 유효한 상태만 유지되게 보장하는 거지.

실제 프로젝트, 특히 큰 팀에서는 캡슐화 없으면 진짜 난장판이야. 누구나 남의 객체 내부 상태를 막 바꿀 수 있으면, 에러랑 충돌이 끝도 없이 생기거든. 캡슐화가 질서를 잡아주고, 각 모듈(클래스)이 자기 데이터에 대해 책임지게 해줘.

이건 SOLID 원칙의 핵심 중 하나야, 특히 단일 책임 원칙(Single Responsibility Principle)이랑 개방/폐쇄 원칙(Open/Closed Principle)에서 중요하지. 나중에 더 자세히 배울 거지만, 일단 캡슐화가 코드를 튼튼하고, 유연하고, 이해하기 쉽고, 유지보수 쉽게 만들어준다는 것만 기억해!


// 캡슐화의 목적: 중요한 데이터 주위에 보이지 않는 울타리 만들기
// 아무도 실수로 바깥에서 "망치지" 못하게!
캡슐화는 객체를 잘못된 변경으로부터 보호해줘

캡슐화는 네 객체의 중요한 데이터 주위에 보이지 않는 울타리를 치는 거랑 비슷해, 아무도 실수로 망치지 못하게. 예를 들어, 네 강아지 나이가 갑자기 음수가 되면 안 되잖아? 그걸 캡슐화가 막아주는 거지. 그리고 클래스를 쓰기 쉽게 만들어줘: 다른 개발자들은 내부 구조를 몰라도 되고, 네가 보여주는 것만 쓰면 돼. 그리고 진짜 좋은 건, 내일 클래스 내부를 바꿔도 — 예를 들어 나이 대신 생일을 저장하게 바꿔도 — 외부에서는 아무것도 안 바뀌는 것처럼 보인다는 거야. 이게 바로 캡슐화의 진짜 가치지!

2. 캡슐화의 장점

왜 이게 네 프로젝트나 커리어에 그렇게 중요할까?

데이터 무결성(Data Integrity):
캡슐화 덕분에 객체의 데이터가 항상 올바르고 논리적인 상태로 유지돼. 이게 프로그램 에러를 엄청 줄여줘. 면접에서 OOP 물어볼 때, 캡슐화가 데이터 무결성 유지에 어떻게 도움되는지 잘 설명하면 점수 확 올라간다!

유연성 & 유지보수성(Flexibility & Maintainability):
예를 들어, 처음엔 강아지 나이를 int Age로 저장했어. 1년 뒤에 고객이 "이제 나이 말고 정확한 생일이 필요해요!"라고 해.

캡슐화 없이: 만약 Agepublic int였다면, 코드 여기저기서 myDog.Age를 직접 썼을 거야. 그럼 intDateTime으로 바꾸고, 나이 계산 로직도 다 고쳐야 해. 진짜 고통임!

캡슐화 했을 때: 만약 private int _age;public int Age { get; set; }로 했다면, 내부 필드를 private DateTime _dateOfBirth;로 바꾸고, get이랑 set 로직만 바꿔서 나이를 생일로부터 계산하면 돼. 외부에서 myDog.Age를 쓰는 코드는 아무것도 모름, 왜냐면 public 인터페이스 Age만 쓰니까. 이걸 결합도 낮추기(loose coupling)라고 해.

이거 완전 마법이지? 클래스 "속"만 바꿨는데, "껍데기"(public 인터페이스)는 그대로야!

디버깅 쉬움(Easier Debugging):
객체 데이터에 문제가 생기면, 캡슐화를 잘 해놨으면 그 문제는 클래스 내부 메서드나 public 프로퍼티에서만 생겨. 버그 찾을 범위가 클래스 하나로 좁아지지, 프로그램 전체를 뒤질 필요 없어.

API 디자인 향상:
클래스를 캡슐화하면, 뭐가 public "계약"(API)이고 뭐가 내부 디테일인지 명확하게 정할 수 있어. 이게 깔끔하고 예측 가능하고 이해하기 쉬운 인터페이스를 만드는 데 도움돼. API가 명확할수록 다른 개발자(혹은 미래의 너)가 네 코드를 쓰기 쉬워.

보안(Security):
C#이 C++처럼 보안에 극도로 민감한 시스템 언어는 아니지만, 캡슐화는 여전히 중요해. 누가, 어떻게 네 데이터에 접근할 수 있는지 컨트롤할 수 있고, 원치 않는 변경이나 민감한 정보 노출도 막을 수 있어.

3. C#에서 캡슐화는 어떻게 할까?

C#에서 캡슐화는 주로 이렇게 해:

접근 제한자(private, public 등):
클래스 필드를 private로 만들어서 외부에서 직접 못 바꾸게 해. 이게 바로 정보 은닉(information hiding)이야.
메서드랑 프로퍼티는 public으로 해서, 데이터랑 동작에 컨트롤된 접근을 제공해. 이게 public 인터페이스지.

프로퍼티(Properties):
이미 배웠듯이, 프로퍼티는 get(읽기)과 set(쓰기) 메서드의 문법 설탕이야. 필드는 숨기고, public facade로 접근하게 해주지. 그리고 set 액세서에 검증 로직도 넣을 수 있고!

예제: 캡슐화 없는 Dog 클래스

먼저 이렇게 하면 안 됨 (캡슐화 없이):


public class Dog
{
    public string Name;
    public int Age;

    public void Bark()
    {
        Console.WriteLine($"{Name} говорит: Гав!");
    }
}

이 버전에서는 다른 클래스가 강아지 이름이랑 나이를 막 바꿀 수 있어. 예를 들어:

Dog dog = new Dog();
dog.Name = "";      // 이름을 빈 문자열로 할 수 있음!
dog.Age = -100;     // 강아지를 엄청 "고대"로 만들 수 있음

현실에서는 이런 일 잘 없지만, 코드에서는 캡슐화 안 하면 진짜 자주 생겨.

데이터 보호: 필드를 private로 만들기

필드를 private로 바꿔보자. 이제 클래스 내부 말고는 직접 못 바꿔:


public class Dog
{
    private string _name;
    private int _age;

    public void Bark()
    {
        Console.WriteLine($"{_name} говорит: Гав!");
    }
}

이제 이런 접근은 불가능:

Dog dog = new Dog();
dog._name = "렉스"; // 컴파일 에러!

프로퍼티(Properties)로 데이터 접근

그래도 강아지 이름을 알고 싶거나(예: 화면에 출력), 가끔 바꿔야 할 때도 있잖아. 그럴 땐 프로퍼티를 쓰면 돼!


public class Dog
{
    private string _name;
    private int _age;

    public string Name
    {
        get { return _name; }
        set
        {
            // 검증 추가: 이름은 빈 문자열이면 안 됨
            if (string.IsNullOrWhiteSpace(value))
            {
                Console.WriteLine("오류: 이름은 비워둘 수 없어!");
            }
            else
            {
                _name = value;
            }
        }
    }

    public int Age
    {
        get { return _age; }
        set
        {
            // 현실적으로: 나이는 음수일 수 없음!
            if (value < 0)
            {
                Console.WriteLine("오류: 나이는 음수일 수 없어!");
            }
            else
            {
                _age = value;
            }
        }
    }

    public void Bark()
    {
        Console.WriteLine($"{_name} говорит: Гав!");
    }
}

이제 데이터는 보호되지만, 컨트롤된 인터페이스로 쓸 수 있어:

Dog dog = new Dog();
dog.Name = "바르보스";      // 문제 없음!
dog.Age = 3;

dog.Name = "";            // 오류 메시지, 값은 안 바뀜!
dog.Age = -1;             // 또 오류

자동 프로퍼티

추가 검증 로직이 필요 없으면, 필드 따로 안 만들고 자동 프로퍼티 쓰면 돼:


public class Dog
{
    public string Name { get; set; }
    public int Age { get; set; }

    public void Bark()
    {
        Console.WriteLine($"{Name} говорит: Гав!");
    }
}

이 경우 Name이랑 Age도 사실상 "캡슐화"된 거야 — 직접 접근은 안 되고, 프로퍼티로만 읽고 쓸 수 있지.

4. 동작도 캡슐화: 필요한 메서드만 공개

캡슐화는 데이터뿐 아니라 메서드에도 적용돼! 어떤 메서드는 클래스 내부에서만 쓰는 "톱니바퀴" 같은 거라서 외부에 보여줄 필요 없어.

예시:


public class Dog
{
    // 내부에서만 사용
    private void WagTail()
    {
        Console.WriteLine("강아지가 꼬리를 흔든다.");
    }

    // 모두에게 공개
    public void Bark()
    {
        WagTail(); // 클래스 내부에서만 숨겨진 메서드 호출
        Console.WriteLine("멍!");
    }
}

이제 강아지 자신 말고는 꼬리를 흔들게 할 수 없어:

Dog dog = new Dog();
dog.WagTail();     // 에러! 메서드가 private임.
dog.Bark();        // Bark 안에서 WagTail 호출됨

차이점: 필드, 메서드, 프로퍼티와 가시성

정리하자면:

클래스 구성요소 private로 할 수 있나? public으로 할 수 있나? 접근 제한 이유?
필드 네 (하지만 비추!) 데이터 보호
메서드 구현 디테일 숨기기
프로퍼티 읽기/쓰기 컨트롤

추천: 필드는 private로 하고, 외부에는 프로퍼티나 메서드로만 보여줘.

2
과제
C# SELF, 레벨 17, 레슨 4
잠금
속성에서 데이터 검증하기
속성에서 데이터 검증하기
2
과제
C# SELF, 레벨 17, 레슨 4
잠금
메서드에 로직이 있는 캡슐화
메서드에 로직이 있는 캡슐화
1
설문조사/퀴즈
속성 (Properties), 레벨 17, 레슨 4
사용 불가능
속성 (Properties)
속성과 접근 제한자
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION