캡슐화 (Encapsulation)

1. 주제의 분류 적절성 평가

캡슐화 (Encapsulation) 는 객체지향 프로그래밍 (Object-Oriented Programming, OOP) 의 4 대 핵심 원리 중 하나로, 복잡한 시스템을 단순화하고 구현 세부사항을 숨겨 인터페이스 중심의 설계를 가능하게 합니다. 이는 소프트웨어 아키텍처의 설계 원칙과 프로그래밍 패러다임 분류에 부합하며, 객체지향 프로그래밍 내에서 필수적인 개념이기 때문에 “Computer Science and Engineering > System and Software Architecture > Principles > Programming Paradigms > Object-Oriented Programming > Primary Principles” 분류는 매우 적절합니다.

1. 주제 분류의 적절성 분석

분류 체계:

  • Computer Science and Engineering

    • System and Software Architecture

      • Principles

        • Programming Paradigms

          • Object-Oriented Programming

            • Primary Principles

분석:

" 캡슐화 " 는 객체 지향 프로그래밍의 4 대 핵심 원칙 (추상화, 캡슐화, 상속, 다형성) 중 하나로, 클래스 내부의 데이터를 보호하고 외부와의 인터페이스를 명확히 정의함으로써 시스템의 안정성과 유지보수성을 향상시킵니다. 따라서 위의 분류 체계는 " 캡슐화 " 의 이론적 및 실무적 중요성을 적절히 반영하고 있습니다.

1. 주제 분류의 적절성 분석

제시된 분류 **“Computer Science and Engineering” > “System and Software Architecture” > “Principles” > “Programming Paradigms” > “Object-Oriented Programming” > “Primary Principles”**는 매우 적절합니다.

근거:

  • 캡슐화는 객체지향 프로그래밍의 4 대 기본 원칙 중 하나 (추상화, 상속, 다형성과 함께)
  • 소프트웨어 아키텍처 설계의 핵심 원리로 모듈화와 정보 은닉을 통한 시스템 구조화 지원
  • 컴퓨터 과학의 프로그래밍 패러다임 이론에서 중요한 위치 차지
  • 시스템 설계와 소프트웨어 아키텍처의 기본 원칙으로 널리 인정받음

2. 200 자 내외 요약

캡슐화는 객체의 데이터와 메서드를 하나의 단위로 묶고, 외부에서 내부 상태에 직접 접근하지 못하도록 보호하는 객체지향 프로그래밍의 기본 원리입니다. 정보 은닉과 접근 제어를 통해 코드의 안정성, 유지보수성, 확장성을 높입니다.

2. 주제 요약 (200 자 내외)

캡슐화는 데이터와 메서드를 하나의 단위로 묶고, 외부로부터의 직접적인 접근을 제한하여 시스템의 복잡성을 관리하고 보안을 강화하는 객체 지향 프로그래밍의 핵심 원칙입니다.

2. 요약 문장 (200 자 내외)

캡슐화는 관련된 데이터와 메서드를 하나의 클래스로 묶고 내부 구현을 외부로부터 숨기는 객체지향 프로그래밍의 핵심 원칙으로, 접근제어자를 통해 정보 은닉을 구현하여 모듈화, 재사용성, 유지보수성을 향상시키는 소프트웨어 설계 기법입니다.

3. 전체 개요 (250 자 내외)

캡슐화는 객체 지향 프로그래밍에서 데이터와 해당 데이터를 조작하는 메서드를 하나의 단위로 묶고, 외부로부터의 직접적인 접근을 제한하여 시스템의 복잡성을 관리하고 보안을 강화하는 원칙입니다. 이를 통해 내부 구현 세부 사항을 숨기고, 명확한 인터페이스를 제공하여 모듈화와 유지보수성을 향상시킵니다. 캡슐화는 정보 은닉 (Information Hiding) 과 밀접한 관련이 있으며, 소프트웨어 설계에서 안정성과 확장성을 확보하는 데 중요한 역할을 합니다.

3. 250 자 내외 개요

캡슐화는 객체지향 설계에서 데이터 (속성) 와 행위 (메서드) 를 하나의 객체로 묶고, 내부 구현을 숨긴 채 외부에는 명확한 인터페이스만 제공하는 원리입니다. 접근 제한자 (private, protected, public) 와 getter/setter, 프로퍼티 등을 활용해 데이터 무결성과 보안을 보장하며, 복잡한 시스템의 유지보수성과 확장성을 높입니다. 과도한 캡슐화는 복잡성을 높일 수 있으므로 적절한 수준의 설계가 중요합니다.

3. 개요 (250 자 내외)

캡슐화는 객체의 상태 (데이터) 와 행위 (메서드) 를 하나의 단위로 결합하고 접근제어자를 통해 내부 구현을 외부로부터 보호하는 객체지향 프로그래밍의 기본 원칙입니다. 정보 은닉을 통해 데이터 무결성을 보장하고, Tell Don’t Ask 원칙을 구현하여 낮은 결합도와 높은 응집도를 달성합니다. 이를 통해 모듈화된 설계, 향상된 보안성, 쉬운 유지보수를 실현할 수 있습니다.

4. 핵심 개념

  • 핵심 개념: 객체의 데이터 (속성) 와 메서드 (행위) 를 하나의 단위로 묶고, 외부로부터 내부 상태를 숨겨 보호하는 객체지향 프로그래밍의 기본 원리.
  • 배경: 복잡한 시스템에서 데이터 무결성과 일관성을 유지하고, 외부 접근을 제한하여 오류를 방지하기 위해 등장.
  • 목적 및 필요성: 데이터 은닉을 통해 객체 내부 상태 보호, 명확한 인터페이스 제공, 유지보수성과 확장성 향상.
  • 주요 기능 및 역할: 데이터와 메서드의 결합, 외부 접근 제한 및 제어, 객체 무결성 보장.
  • 특징: 정보 은닉 (Information Hiding), 접근 제어 (Access Control), 인터페이스 중심 설계.
  • 핵심 원칙: private, protected, public 접근 제한자 사용, getter/setter 메서드 활용.
  • 주요 원리: 내부 구현 감추기, 외부와의 명확한 인터페이스 제공.
  • 작동 원리: 객체 내부 데이터는 private 으로 선언하고, 외부에서는 public 메서드를 통해서만 접근 가능. 메서드 호출 시 내부 상태 변경이나 검증 수행.

4. 핵심 개념

정의:

캡슐화는 객체 지향 프로그래밍에서 데이터와 해당 데이터를 조작하는 메서드를 하나의 단위로 묶고, 외부로부터의 직접적인 접근을 제한하여 시스템의 복잡성을 관리하고 보안을 강화하는 원칙입니다.

주요 목적:

  • 데이터 보호: 외부로부터의 직접적인 접근을 제한하여 데이터의 무결성을 유지합니다.

  • 모듈화: 데이터와 메서드를 하나의 단위로 묶어 모듈화된 구조를 형성합니다.

  • 유지보수성 향상: 내부 구현 세부 사항을 숨기고, 명확한 인터페이스를 제공하여 유지보수를 용이하게 합니다.

구현 방법:

  • 접근 제한자 사용: private, protected, public 등의 접근 제한자를 사용하여 데이터의 접근 범위를 정의합니다.

  • Getter/Setter 메서드: 데이터에 대한 접근과 수정을 제어하기 위해 Getter 와 Setter 메서드를 사용합니다.(celerdata.com)

예시 (Java):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Person {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age > 0){
            this.age = age;
        }
    }
}

위의 예시에서 nameageprivate 으로 선언되어 외부에서 직접 접근할 수 없으며, getName(), setName(), getAge(), setAge() 메서드를 통해 간접적으로 접근할 수 있습니다.

4. 핵심 개념

이론과 실무에서 반드시 알아야 하는 개념들

기본 개념:

  • 데이터와 메서드의 결합: 관련 있는 변수와 함수를 클래스로 묶는 작업
  • 정보 은닉 (Information Hiding): 객체의 내부 구현을 외부에서 접근할 수 없도록 숨기는 것
  • 접근제어자 (Access Modifiers): public, private, protected 를 통한 접근 권한 제어
  • 캡슐 (Capsule) 개념: 약의 캡슐처럼 내용물을 보호하는 외부 껍질

심화 개념:

  • Tell, Don’t Ask 원칙: 데이터를 요청하지 말고 처리를 요청하는 설계 원칙
  • 데이터 무결성 (Data Integrity): 올바르지 않은 데이터 수정을 방지
  • 모듈화 (Modularization): 독립적인 단위로 기능을 분리하여 설계
  • 결합도와 응집도: 낮은 결합도와 높은 응집도를 통한 좋은 설계

배경

캡슐화의 개념은 1972 년 David Parnas 가 정보 은닉을 처음 제시한 것에서 시작되었습니다. 1973 년 Zelis 가 ’encapsulation’ 이라는 용어를 도입하여 클래스 내부 데이터 접근을 제한하는 개념을 설명했습니다.

역사적 발전:

  • 1970 년대: 모듈화 프로그래밍에서 정보 은닉 개념 등장
  • 1980 년대: 객체지향 프로그래밍 언어에서 캡슐화 구현
  • 1990 년대: 객체지향 설계 원칙의 핵심으로 자리 잡음
  • 2000 년대 이후: 마이크로서비스, API 설계 등 대규모 시스템에 적용

목적 및 필요성

주요 목적:

  1. 데이터 보호: 외부로부터 직접적인 데이터 접근을 차단
  2. 모듈화 구현: 독립적인 컴포넌트로 시스템 구성
  3. 유지보수성 향상: 내부 구현 변경 시 외부 영향 최소화
  4. 재사용성 증대: 독립적인 모듈을 다양한 환경에서 재사용

필요성:

  • 복잡성 관리: 대규모 소프트웨어의 복잡성을 체계적으로 관리
  • 팀 개발: 여러 개발자가 협업할 때 인터페이스 통일
  • 오류 방지: 잘못된 데이터 접근으로 인한 버그 예방
  • 보안 강화: 민감한 데이터의 무단 접근 방지

주요 기능 및 역할

핵심 기능:

  1. 데이터 번들링 (Data Bundling): 관련 데이터와 메서드를 하나의 단위로 묶음
  2. 접근 제어 (Access Control): 접근제어자를 통한 세밀한 권한 관리
  3. 인터페이스 제공: 외부와의 상호작용을 위한 공개 메서드 제공
  4. 상태 보호: 객체의 내부 상태를 일관되게 유지

주요 역할:

  • 추상화 지원: 복잡한 내부 구현을 단순한 인터페이스로 추상화
  • 결합도 감소: 모듈 간 의존성을 최소화
  • 응집도 증가: 관련 기능을 한 곳에 집중
  • 확장성 제공: 새로운 기능 추가 시 기존 코드 영향 최소화

주요 기능 및 역할

  • 데이터 보호: 외부로부터의 직접적인 접근을 제한하여 데이터의 무결성을 유지합니다.

  • 모듈화: 데이터와 메서드를 하나의 단위로 묶어 모듈화된 구조를 형성합니다.

  • 유지보수성 향상: 내부 구현 세부 사항을 숨기고, 명확한 인터페이스를 제공하여 유지보수를 용이하게 합니다.

특징

  • 정보 은닉: 내부 구현 세부 사항을 숨기고, 외부에는 명확한 인터페이스만을 제공합니다.

  • 접근 제어: 접근 제한자를 사용하여 데이터의 접근 범위를 제어합니다.

  • 유연성: 내부 구현을 변경하더라도 외부에 영향을 주지 않도록 설계할 수 있습니다.

특징

기본 특징:

  • 정보 은닉성: 내부 구현 세부사항을 외부에서 알 수 없음
  • 인터페이스 일관성: 공개된 메서드를 통한 일관된 상호작용
  • 데이터 무결성: 유효하지 않은 데이터 상태 방지
  • 모듈 독립성: 각 모듈이 독립적으로 동작

고급 특징:

  • 다형성 지원: 동일한 인터페이스로 다양한 구현 제공
  • 상속 호환성: 부모 클래스의 캡슐화를 자식 클래스가 상속
  • 컴파일 시간 검증: 접근 권한 위반을 컴파일 단계에서 감지
  • 런타임 안전성: 실행 중 잘못된 접근 방지

핵심 원칙

  • 정보 은닉 (Information Hiding): 내부 구현 세부 사항을 숨기고, 외부에는 명확한 인터페이스만을 제공합니다.

  • 단일 책임 원칙 (Single Responsibility Principle): 각 클래스나 모듈은 하나의 책임만을 가져야 합니다.

  • 개방 - 폐쇄 원칙 (Open/Closed Principle): 기능 확장은 가능하되, 기존 코드는 수정하지 않아야 합니다.

핵심 원칙

SOLID 원칙과의 연관성:

  1. 단일 책임 원칙 (SRP): 각 클래스는 하나의 책임만 가져야 함
  2. 개방 - 폐쇄 원칙 (OCP): 확장에는 열려있고 수정에는 닫혀있어야 함
  3. 리스코프 치환 원칙 (LSP): 서브타입은 기반 타입으로 치환 가능해야 함
  4. 인터페이스 분리 원칙 (ISP): 클라이언트는 사용하지 않는 인터페이스에 의존하지 않아야 함
  5. 의존성 역전 원칙 (DIP): 상위 모듈은 하위 모듈에 의존하지 않아야 함

캡슐화 고유 원칙:

  • 최소 권한 원칙: 필요한 최소한의 접근 권한만 부여
  • Tell, Don’t Ask: 객체에게 작업을 요청하되 내부 상태를 묻지 말 것
  • 데이터 중심 설계 회피: 기능 중심의 설계 추구
  • 인터페이스 안정성: 공개 인터페이스는 가능한 변경하지 않음

작동 원리

캡슐화는 클래스 내부의 데이터를 private 으로 선언하고, 외부에서는 public 으로 선언된 Getter 와 Setter 메서드를 통해 간접적으로 접근하도록 설계합니다. 이를 통해 데이터의 무결성을 유지하고, 외부로부터의 직접적인 접근을 제한하여 시스템의 안정성과 보안을 강화합니다.

주요 원리

캡슐화 작동 원리 다이어그램:

graph TB
    subgraph "캡슐화된 클래스"
        A[Public Interface] --> B[Protected Members]
        B --> C[Private Data]
        B --> D[Private Methods]
        
        A --> E[Public Methods]
        E --> F[Data Validation]
        F --> C
        E --> G[Business Logic]
        G --> D
    end
    
    H[External Client] --> A
    H -.X.C
    H -.X.D

작동 원리:

  1. 외부 클라이언트는 오직 Public Interface를 통해서만 객체와 상호작용
  2. Public Methods는 데이터 검증과 비즈니스 로직을 수행
  3. Private DataPrivate Methods는 외부에서 직접 접근 불가
  4. Protected Members는 상속 관계에서만 접근 가능

구조 및 아키텍처

필수 구성요소

구성 요소기능/역할특징
데이터 (속성)객체가 가지는 상태 정보, 보통 private 선언외부 직접 접근 불가
메서드 (행위)데이터에 접근하거나 조작하는 함수, public 제공인터페이스 역할
접근 제한자private, protected, public 등으로 접근 범위 제어정보 은닉 및 보안 강화

선택 구성요소

구성 요소기능/역할특징
getter/setter데이터 접근 및 변경 시 검증 로직 포함 가능무결성 및 유효성 보장
프로퍼티언어에 따라 속성 접근을 메서드처럼 처리Python 등에서 활용
인터페이스/추상 클래스외부에 노출할 인터페이스 정의구현과 분리, 확장성 강화

구조 다이어그램 (mermaid)

classDiagram
    class Person {
        -name: str
        -age: int
        +get_name(): str
        +get_age(): int
        +set_age(age: int)
    }

구조 및 아키텍처

구성 요소 및 역할

캡슐화는 다음과 같은 주요 구성 요소로 이루어집니다:

  • 데이터 필드 (Data Fields): 클래스 내부에 선언된 변수로, 객체의 상태를 나타냅니다. 일반적으로 private 접근 제한자를 사용하여 외부에서 직접 접근하지 못하도록 합니다.

  • 메서드 (Methods): 데이터 필드를 조작하거나 정보를 제공하는 함수입니다. public 접근 제한자를 사용하여 외부에서 호출할 수 있도록 합니다.

  • 접근 제한자 (Access Modifiers): 클래스의 멤버 (데이터 필드 및 메서드) 에 대한 접근 권한을 정의합니다. 주요 접근 제한자는 다음과 같습니다:

    • private: 동일 클래스 내에서만 접근 가능

    • protected: 동일 패키지 또는 서브클래스에서 접근 가능

    • public: 모든 클래스에서 접근 가능

  • Getter/Setter 메서드: private 로 선언된 데이터 필드에 대한 간접적인 접근을 제공하는 메서드입니다. 데이터의 무결성을 유지하고, 외부에서의 직접적인 수정이나 조회를 방지합니다.

다이어그램 (Mermaid)

classDiagram
    class Person {
        -name: String
        -age: int
        +getName(): String
        +setName(name: String): void
        +getAge(): int
        +setAge(age: int): void
    }

위의 다이어그램은 Person 클래스의 구조를 나타내며, nameage 필드는 private 으로 선언되어 외부에서 직접 접근할 수 없고, getName(), setName(), getAge(), setAge() 메서드를 통해 간접적으로 접근할 수 있습니다.

구조 및 아키텍처

캡슐화 구조 다이어그램:

classDiagram
    class EncapsulatedClass {
        <<interface>>
        +publicMethod1()
        +publicMethod2()
        #protectedField
        #protectedMethod()
        -privateField1
        -privateField2
        -privateMethod1()
        -privateMethod2()
    }
    
    class Client {
        +useEncapsulatedClass()
    }
    
    class SubClass {
        +extendedMethod()
    }
    
    Client --> EncapsulatedClass : uses public interface
    SubClass --|> EncapsulatedClass : inherits
    
    note for EncapsulatedClass "접근 제어자:\n+ public\n# protected\nprivate"

구성 요소

필수 구성요소:

  1. 클래스 선언: 캡슐화의 기본 단위
  2. Private 멤버: 외부 접근을 차단하는 내부 데이터와 메서드
  3. Public 인터페이스: 외부와의 상호작용을 위한 공개 메서드
  4. 접근제어자: private, protected, public 을 통한 접근 권한 제어

선택 구성요소:

  1. Static 멤버: 클래스 레벨에서 공유되는 데이터와 메서드
  2. Final/Const 멤버: 변경 불가능한 상수
  3. Abstract 메서드: 하위 클래스에서 구현해야 하는 메서드
  4. Inner Class: 캡슐화를 더욱 세밀하게 구현하는 내부 클래스

각 구성요소의 기능과 역할:

구성요소기능역할특징
Private Fields데이터 은닉객체 상태 보호외부 접근 불가
Public Methods인터페이스 제공외부와의 상호작용데이터 검증 포함
Protected Members상속 지원하위 클래스 접근 허용패키지/상속 레벨 접근
Getter/Setter제어된 접근데이터 읽기/쓰기 제어유효성 검사 가능

구현 기법

정의

캡슐화는 객체 지향 프로그래밍에서 데이터와 해당 데이터를 조작하는 메서드를 하나의 단위로 묶고, 외부로부터의 직접적인 접근을 제한하여 시스템의 복잡성을 관리하고 보안을 강화하는 원칙입니다.

구성

  • 접근 제한자 사용: private, protected, public 등의 접근 제한자를 사용하여 데이터의 접근 범위를 정의합니다.

  • Getter/Setter 메서드: 데이터에 대한 접근과 수정을 제어하기 위해 Getter 와 Setter 메서드를 사용합니다.

목적

  • 데이터 보호: 외부로부터의 직접적인 접근을 제한하여 데이터의 무결성을 유지합니다.

  • 모듈화: 데이터와 메서드를 하나의 단위로 묶어 모듈화된 구조를 형성합니다.

  • 유지보수성 향상: 내부 구현 세부 사항을 숨기고, 명확한 인터페이스를 제공하여 유지보수를 용이하게 합니다.

실제 예시 (Java)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class BankAccount {
    private double balance;

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

    public double getBalance() {
        return balance;
    }

    public void deposit(double amount) {
        if(amount > 0){
            balance += amount;
        }
    }

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

위의 예시에서 balance 필드는 private 으로 선언되어 외부에서 직접 접근할 수 없으며, getBalance(), deposit(), withdraw() 메서드를 통해 간접적으로 접근할 수 있습니다. 이를 통해 계좌의 잔액을 안전하게 보호하고, 무결성을 유지할 수 있습니다.

구현 기법

기법정의/구성목적/예시
접근 제한자 사용private, protected, public 키워드 활용접근 제어, 정보 은닉, 보안 강화
getter/setter 메서드데이터 접근 및 변경 시 검증 로직 포함 가능무결성 보장, 예외 처리, 유효성 검사
프로퍼티 (property)언어별 속성 접근을 메서드처럼 처리Python 의 @property 등
인터페이스/추상 클래스외부에 노출할 인터페이스 정의구현과 분리, 다형성 지원

구현 예시 (Python)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Person:
    def __init__(self, name, age):
        self.__name = name  # private 변수
        self.__age = age    # private 변수

    # getter 메서드
    def get_name(self):
        return self.__name

    # setter 메서드
    def set_age(self, age):
        if age > 0:
            self.__age = age
        else:
            print("나이는 0보다 커야 합니다.")

    def get_age(self):
        return self.__age

# 사용 예시
person = Person("홍길동", 30)
print(person.get_name())  # 홍길동
print(person.get_age())   # 30
person.set_age(35)
print(person.get_age())   # 35
person.set_age(-5)        # 나이는 0보다 커야 합니다.

구현 기법

1. 접근제어자 기법

  • 정의: 클래스 멤버의 접근 권한을 제어하는 키워드
  • 구성: private, protected, public, default/package-private
  • 목적: 정보 은닉과 캡슐화 경계 설정
  • 실제 예시: Java 에서 은행 계좌 클래스의 잔액 필드를 private 으로 선언
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class BankAccount {
    private double balance; // private으로 직접 접근 차단
    
    public double getBalance() { // public getter로 읽기 허용
        return balance;
    }
    
    public void deposit(double amount) { // 검증 로직 포함
        if (amount > 0) {
            balance += amount;
        }
    }
}

2. Getter/Setter 패턴

  • 정의: private 필드에 대한 제어된 접근을 제공하는 메서드 쌍
  • 구성: getter(읽기), setter(쓰기) 메서드
  • 목적: 데이터 접근 시 유효성 검사와 비즈니스 로직 적용
  • 실제 예시: E-commerce 시스템에서 상품 가격 설정 시 음수 방지
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Product:
    def __init__(self):
        self._price = 0
    
    @property
    def price(self):  # getter
        return self._price
    
    @price.setter
    def price(self, value):  # setter with validation
        if value < 0:
            raise ValueError("가격은 음수일 수 없습니다")
        self._price = value

3. 팩토리 패턴을 통한 캡슐화

  • 정의: 객체 생성 과정을 캡슐화하여 클라이언트로부터 숨기는 패턴
  • 구성: Factory 클래스, Product 인터페이스, Concrete Products
  • 목적: 객체 생성 로직의 복잡성을 숨기고 일관된 인터페이스 제공
  • 실제 예시: 데이터베이스 연결 팩토리에서 다양한 DB 타입 지원
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class DatabaseConnectionFactory {
    static createConnection(type, config) {
        switch(type) {
            case 'mysql':
                return new MySQLConnection(config);
            case 'postgresql':
                return new PostgreSQLConnection(config);
            default:
                throw new Error('지원하지 않는 데이터베이스 타입');
        }
    }
}

4. 모듈 패턴 (JavaScript)

  • 정의: 클로저를 활용하여 private 변수와 메서드를 구현하는 패턴
  • 구성: IIFE(즉시 실행 함수), 반환 객체, 클로저
  • 목적: JavaScript 에서 진정한 private 멤버 구현
  • 실제 예시: 웹 애플리케이션에서 사용자 세션 관리 모듈
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
const SessionManager = (function() {
    let currentUser = null; // private 변수
    
    function validateUser(user) { // private 함수
        return user && user.id && user.name;
    }
    
    return { // public 인터페이스
        login: function(user) {
            if (validateUser(user)) {
                currentUser = user;
                return true;
            }
            return false;
        },
        
        getCurrentUser: function() {
            return currentUser ? {currentUser} : null; // 복사본 반환
        }
    };
})();

장점과 단점

구분항목설명
✅ 장점데이터 보호외부로부터 직접적인 데이터 접근을 차단하여 무결성 보장
모듈화관련 기능을 하나의 단위로 묶어 독립적인 모듈 구성
유지보수성내부 구현 변경 시 외부 코드에 미치는 영향 최소화
재사용성독립적인 모듈로 다양한 환경에서 재사용 가능
보안성민감한 정보의 접근을 제어하여 보안 강화
코드 가독성명확한 인터페이스로 코드 이해도 향상
⚠ 단점성능 오버헤드메서드 호출을 통한 간접 접근으로 인한 성능 저하
복잡성 증가단순한 작업도 메서드를 통해 수행해야 하는 복잡성
개발 시간 증가Getter/Setter 메서드 작성 등 추가 코드 작성 필요
메모리 사용량추가 메서드로 인한 메모리 사용량 증가

단점 해결 방법:

  • 성능 최적화: 컴파일러 최적화 활용, 인라인 함수 사용
  • 코드 생성 도구: IDE 의 자동 코드 생성 기능 활용
  • 적절한 수준 적용: 모든 필드에 Getter/Setter 를 만들지 않고 필요한 경우만 적용
  • 언어별 특화 기능: Python 의 property, C#의 auto-property 등 활용

장점과 단점

구분항목설명
✅ 장점데이터 보호객체 내부 상태를 외부로부터 보호하여 무결성 유지
유지보수성내부 구현 변경 시 외부 영향 최소화
모듈화인터페이스 중심 설계로 코드 재사용 및 확장 용이
⚠ 단점설계 복잡성적절한 접근 제어 설계 필요, 과도한 캡슐화는 복잡성 증가
성능 저하접근자 메서드 호출로 인한 오버헤드 가능
  • 단점 해결 방법: 최소 권한 원칙 적용, 인터페이스 단순화, 프로파일링 및 핫스팟 최적화, 설계 리뷰 및 리팩토링.

장점과 단점

구분항목설명
✅ 장점데이터 보호외부로부터의 직접적인 접근을 제한하여 데이터의 무결성을 유지합니다.
모듈화데이터와 메서드를 하나의 단위로 묶어 모듈화된 구조를 형성합니다.
유지보수성 향상내부 구현 세부 사항을 숨기고, 명확한 인터페이스를 제공하여 유지보수를 용이하게 합니다.
코드 재사용성 향상캡슐화된 클래스는 다른 프로그램에서도 재사용이 용이합니다.
⚠ 단점코드 복잡성 증가Getter/Setter 메서드의 추가로 코드의 양이 증가할 수 있습니다.
성능 저하 가능성메서드를 통한 간접적인 접근으로 인해 성능이 저하될 수 있습니다.
유연성 제한엄격한 접근 제한으로 인해 필요한 경우에도 데이터에 접근하기 어려울 수 있습니다.

단점 해결 방법:

  • 자동화 도구 활용: IDE 의 기능을 활용하여 Getter/Setter 메서드를 자동으로 생성하여 코드 작성의 효율성을 높일 수 있습니다.

  • 적절한 접근 제한자 선택: 필요에 따라 protectedpackage-private 접근 제한자를 사용하여 유연성을 확보할 수 있습니다.

  • 성능 최적화: 빈번한 데이터 접근이 필요한 경우, 캐싱 등의 기법을 활용하여 성능 저하를 최소화할 수 있습니다.


도전 과제

  • 과도한 캡슐화: 모든 필드를 private 으로 선언하고, 불필요한 Getter/Setter 메서드를 생성하는 것은 오히려 코드의 복잡성을 증가시킬 수 있습니다.

    • 해결책: 실제로 외부에서 접근이 필요한 필드에 대해서만 Getter/Setter 메서드를 생성하고, 불필요한 메서드는 생략합니다.
  • 테스트의 어려움: private 으로 선언된 필드는 테스트 코드에서 직접 접근할 수 없어 테스트가 어려울 수 있습니다.

    • 해결책: 테스트를 위해 필요한 경우, 패키지 접근 수준을 활용하거나, 테스트 전용 메서드를 제공하여 테스트의 용이성을 확보합니다.
  • 성능 저하: Getter/Setter 메서드를 통한 간접적인 접근은 성능 저하를 초래할 수 있습니다.

    • 해결책: 성능이 중요한 경우, 직접 접근을 허용하거나, 캐싱 등의 기법을 활용하여 성능을 최적화합니다.

도전 과제

  • 적절한 접근 제어 수준 결정
  • 캡슐화와 유연성 간 균형 유지

도전 과제

1. 과도한 Getter/Setter 사용

  • 설명: 모든 private 필드에 대해 Getter/Setter 를 만드는 안티패턴
  • 해결책: Tell, Don’t Ask 원칙 적용, 필요한 경우만 제공

2. 캡슐화 위반

  • 설명: 내부 객체의 참조를 직접 반환하여 외부에서 수정 가능하게 하는 문제
  • 해결책: 방어적 복사 (Defensive Copy) 또는 불변 객체 반환

3. 인터페이스 설계의 어려움

  • 설명: 적절한 추상화 수준의 공개 인터페이스 설계의 복잡성
  • 해결책: 도메인 중심 설계, 사용자 관점에서의 인터페이스 설계

4. 상속과 캡슐화의 충돌

  • 설명: 상속 시 부모 클래스의 캡슐화가 깨질 수 있는 문제
  • 해결책: 컴포지션 우선 원칙, protected 접근제어자 신중한 사용

분류 기준에 따른 종류 및 유형

분류 기준유형설명예시
언어별 구현강한 캡슐화언어 차원에서 접근제어 강제Java, C#의 private
약한 캡슐화관례적 캡슐화 (언어적 강제 없음)Python 의 _private
접근 범위클래스 레벨클래스 내부에서만 접근 가능private 멤버
패키지 레벨같은 패키지 내에서 접근 가능default/package-private
상속 레벨상속 관계에서 접근 가능protected 멤버
전역 레벨모든 곳에서 접근 가능public 멤버
적용 범위데이터 캡슐화데이터 필드의 접근 제어private 변수
기능 캡슐화메서드의 접근 제어private 메서드
타입 캡슐화내부 클래스/타입의 은닉중첩 클래스
구현 방식정적 캡슐화컴파일 시간에 결정되는 접근 제어접근제어자
동적 캡슐화런타임에 결정되는 접근 제어프록시 패턴

분류 기준에 따른 종류 및 유형

분류 기준유형설명
접근 제어 수준private, protected, public접근 범위에 따른 분류
구현 방식명시적 접근자, 프로퍼티getter/setter 또는 프로퍼티 사용 여부

분류 기준에 따른 종류 및 유형

캡슐화는 구현 방식에 따라 다음과 같이 분류할 수 있습니다:

분류 기준유형설명
구현 대상데이터 멤버 캡슐화클래스의 데이터 멤버를 private 으로 선언하고, public 메서드를 통해 접근을 제어하는 방식입니다.
구현 대상메서드 캡슐화내부 구현에 사용되는 메서드를 private 으로 선언하여 외부에서 접근할 수 없도록 하는 방식입니다.
구현 대상클래스 캡슐화내부 구현에 사용되는 클래스를 private 으로 선언하여 외부에서 접근할 수 없도록 하는 방식입니다.
접근 수준완전 캡슐화모든 데이터 멤버와 메서드를 private 으로 선언하고, 필요한 경우에만 public 메서드를 통해 접근을 허용하는 방식입니다.
접근 수준부분 캡슐화일부 데이터 멤버나 메서드를 public 또는 protected 으로 선언하여 외부에서의 접근을 허용하는 방식입니다.
설계 목적정보 은닉 중심내부 구현 세부 사항을 숨기고, 외부에는 명확한 인터페이스만을 제공하여 시스템의 안정성과 보안을 강화하는 방식입니다.
설계 목적모듈화 중심관련된 데이터와 메서드를 하나의 단위로 묶어 모듈화된 구조를 형성하여 유지보수성과 재사용성을 향상시키는 방식입니다.

구현 예시

Python 으로 구현한 은행 계좌 시스템:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
class BankAccount:
    """은행 계좌 클래스 - 캡슐화 구현 예시"""
    
    def __init__(self, account_number, initial_balance=0):
        # Private 속성 (Python 관례상 _로 시작)
        self._account_number = account_number
        self._balance = initial_balance
        self._transaction_history = []
        self.__pin = None  # 더 강한 은닉 (__로 시작)
    
    # Public 메서드 - 외부 인터페이스
    def deposit(self, amount):
        """입금 처리"""
        if self._validate_amount(amount):
            self._balance += amount
            self._record_transaction("입금", amount)
            return True
        return False
    
    def withdraw(self, amount, pin):
        """출금 처리 (PIN 인증 필요)"""
        if self._authenticate(pin) and self._validate_amount(amount):
            if self._balance >= amount:
                self._balance -= amount
                self._record_transaction("출금", amount)
                return True
            else:
                raise ValueError("잔액이 부족합니다")
        return False
    
    @property
    def balance(self):
        """잔액 조회 (읽기 전용)"""
        return self._balance
    
    @property
    def account_number(self):
        """계좌번호 조회 (읽기 전용)"""
        return self._account_number
    
    def set_pin(self, pin):
        """PIN 설정"""
        if len(str(pin)) == 4:
            self.__pin = pin
            return True
        raise ValueError("PIN은 4자리 숫자여야 합니다")
    
    def get_transaction_history(self, pin):
        """거래 내역 조회 (PIN 인증 필요)"""
        if self._authenticate(pin):
            return self._transaction_history.copy()  # 방어적 복사
        raise ValueError("PIN이 일치하지 않습니다")
    
    # Private 메서드 - 내부 구현
    def _validate_amount(self, amount):
        """금액 유효성 검사"""
        return isinstance(amount, (int, float)) and amount > 0
    
    def _authenticate(self, pin):
        """PIN 인증"""
        return self.__pin is not None and self.__pin == pin
    
    def _record_transaction(self, transaction_type, amount):
        """거래 기록"""
        from datetime import datetime
        transaction = {
            'type': transaction_type,
            'amount': amount,
            'timestamp': datetime.now(),
            'balance': self._balance
        }
        self._transaction_history.append(transaction)

# 사용 예시
account = BankAccount("123-456-789", 1000)
account.set_pin(1234)
account.deposit(500)
print(f"현재 잔액: {account.balance}")  # 1500
account.withdraw(200, 1234)
print(f"출금 후 잔액: {account.balance}")  # 1300

JavaScript 로 구현한 사용자 관리 시스템:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
class UserManager {
    constructor() {
        // Private 필드 (ES2022 문법)
        #users = new Map();
        #currentUser = null;
        #sessionTimeout = 30 * 60 * 1000; // 30분
    }
    
    // Public 메서드
    register(username, password, email) {
        if (this.#validateUserData(username, password, email)) {
            const userId = this.#generateUserId();
            const user = {
                id: userId,
                username: username,
                password: this.#hashPassword(password),
                email: email,
                createdAt: new Date(),
                isActive: true
            };
            
            this.#users.set(userId, user);
            return { success: true, userId: userId };
        }
        return { success: false, error: "유효하지 않은 사용자 데이터" };
    }
    
    login(username, password) {
        const user = this.#findUserByUsername(username);
        if (user && this.#verifyPassword(password, user.password)) {
            this.#currentUser = {
                user,
                loginTime: new Date()
            };
            this.#setSessionTimer();
            return { success: true, user: this.#getSafeUserData(user) };
        }
        return { success: false, error: "로그인 실패" };
    }
    
    getCurrentUser() {
        if (this.#currentUser && this.#isSessionValid()) {
            return this.#getSafeUserData(this.#currentUser);
        }
        return null;
    }
    
    logout() {
        this.#currentUser = null;
        return { success: true, message: "로그아웃되었습니다" };
    }
    
    // Private 메서드
    #validateUserData(username, password, email) {
        return username && username.length >= 3 &&
               password && password.length >= 8 &&
               email && this.#isValidEmail(email);
    }
    
    #isValidEmail(email) {
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        return emailRegex.test(email);
    }
    
    #hashPassword(password) {
        // 실제로는 bcrypt 등을 사용해야 함
        return btoa(password + "salt");
    }
    
    #verifyPassword(password, hashedPassword) {
        return this.#hashPassword(password) === hashedPassword;
    }
    
    #generateUserId() {
        return 'user_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
    }
    
    #findUserByUsername(username) {
        for (let user of this.#users.values()) {
            if (user.username === username) {
                return user;
            }
        }
        return null;
    }
    
    #getSafeUserData(user) {
        const { password, safeData } = user;
        return safeData;
    }
    
    #isSessionValid() {
        if (!this.#currentUser) return false;
        const now = new Date();
        const loginTime = new Date(this.#currentUser.loginTime);
        return (now - loginTime) < this.#sessionTimeout;
    }
    
    #setSessionTimer() {
        setTimeout(() => {
            if (this.#currentUser) {
                this.#currentUser = null;
                console.log("세션이 만료되었습니다");
            }
        }, this.#sessionTimeout);
    }
}

// 사용 예시
const userManager = new UserManager();
userManager.register("john_doe", "password123", "john@example.com");
const loginResult = userManager.login("john_doe", "password123");
console.log("로그인 결과:", loginResult);

실무 적용 예시

분야시스템적용 방식효과
금융인터넷 뱅킹계좌 정보, 거래 내역 캡슐화데이터 보안, 무결성 보장
E-commerce온라인 쇼핑몰상품 정보, 주문 처리 로직 캡슐화비즈니스 로직 보호, 확장성
게임MMORPG캐릭터 스탯, 아이템 시스템 캡슐화치팅 방지, 게임 밸런스
IoT스마트 홈센서 데이터, 제어 로직 캡슐화디바이스 추상화, 호환성
의료병원 정보시스템환자 정보, 진료 기록 캡슐화개인정보 보호, 접근 제어
교육LMS 플랫폼학습자 정보, 성적 관리 캡슐화데이터 보호, 권한 관리

실무 적용 예시

캡슐화는 다양한 실무 환경에서 활용됩니다. 다음은 그 예시입니다:

적용 분야적용 사례설명
웹 애플리케이션사용자 정보 관리 클래스에서 사용자 정보를 private 으로 선언하고, Getter/Setter 메서드를 통해 접근을 제어합니다.사용자 정보의 무결성과 보안을 유지하며, 외부에서의 직접적인 접근을 방지합니다.
모바일 애플리케이션위치 정보 관리 클래스에서 위치 정보를 private 으로 선언하고, Getter/Setter 메서드를 통해 접근을 제어합니다.사용자의 위치 정보 보호와 관련된 보안 요구사항을 충족시킵니다.
금융 시스템계좌 정보 관리 클래스에서 계좌 정보를 private 으로 선언하고, Getter/Setter 메서드를 통해 접근을 제어합니다.계좌 정보의 무결성과 보안을 유지하며, 외부에서의 직접적인 접근을 방지합니다.
IoT 시스템센서 데이터 관리 클래스에서 센서 데이터를 private 으로 선언하고, Getter/Setter 메서드를 통해 접근을 제어합니다.센서 데이터의 무결성과 보안을 유지하며, 외부에서의 직접적인 접근을 방지합니다.
게임 개발게임 캐릭터 클래스에서 캐릭터의 상태 정보를 private 으로 선언하고, Getter/Setter 메서드를 통해 접근을 제어합니다.게임 캐릭터의 상태 정보를 보호하며, 외부에서의 직접적인 접근을 방지합니다.

실무 적용 예시

분야사례설명
웹 개발사용자 정보 보호민감 데이터 은닉 및 접근 제어 구현
API 설계인터페이스 제공외부에 노출할 기능과 데이터 제한
라이브러리 개발내부 구현 은닉유지보수성 및 확장성 강화

활용 사례

  • 금융 시스템에서 고객 정보 보호: 내부 데이터는 private 으로 선언하고, getter/setter 로 접근 제어.
  • 시스템 구성: 사용자 객체 → private 속성 → getter/setter → 외부 시스템
  • Workflow:
    1. 외부에서 객체 생성
    2. getter/setter 를 통해 데이터 접근 및 검증
    3. 내부 상태 보호 및 무결성 유지
  • 역할: 민감 정보 보호, 시스템 신뢰성 및 유지보수성 강화

활용 사례

금융 시스템에서의 캡슐화 활용 사례

금융 시스템에서는 고객의 계좌 정보를 보호하고, 무결성을 유지하기 위해 캡슐화를 적극적으로 활용합니다. 예를 들어, 계좌 정보 관리 클래스에서 계좌 번호, 잔액 등의 정보를 private 으로 선언하고, public 메서드를 통해서만 접근을 허용합니다. 이를 통해 외부에서의 직접적인 접근을 방지하고, 데이터의 무결성과 보안을 유지할 수 있습니다.

시스템 구성 다이어그램 (Mermaid)

classDiagram
    class Account {
        -accountNumber: String
        -balance: double
        +getAccountNumber(): String
        +getBalance(): double
        +deposit(amount: double): void
        +withdraw(amount: double): void
    }

    class BankingSystem {
        -accounts: List<Account>
        +createAccount(accountNumber: String): Account
        +getAccount(accountNumber: String): Account
    }

    BankingSystem --> Account

워크플로우

  1. 사용자가 계좌를 생성합니다.

  2. BankingSystem 클래스의 createAccount 메서드를 호출하여 새로운 Account 객체를 생성합니다.(en.wikipedia.org)

  3. Account 클래스의 deposit 또는 withdraw 메서드를 통해 잔액을 조작합니다.

  4. getBalance 메서드를 통해 현재 잔액을 조회합니다.

담당 역할

  • Account 클래스: 계좌 정보 및 잔액을 관리하며, 외부에서의 직접적인 접근을 방지합니다.

  • BankingSystem 클래스: 계좌의 생성 및 조회를 담당하며, Account 클래스와의 인터페이스 역할을 수행합니다.

활용 사례: 대형 E-commerce 플랫폼의 주문 관리 시스템

시스템 구성:

graph TB
    subgraph "Frontend Layer"
        A[Web Interface]
        B[Mobile App]
        C[Admin Panel]
    end
    
    subgraph "API Gateway"
        D[Authentication Service]
        E[Rate Limiting]
        F[Request Routing]
    end
    
    subgraph "Microservices"
        G[Order Service]
        H[Payment Service]
        I[Inventory Service]
        J[User Service]
        K[Notification Service]
    end
    
    subgraph "Data Layer"
        L[(Order DB)]
        M[(Payment DB)]
        N[(Inventory DB)]
        O[(User DB)]
    end
    
    A --> D
    B --> D
    C --> D
    
    D --> G
    D --> H
    D --> I
    D --> J
    
    G --> L
    H --> M
    I --> N
    J --> O
    
    G --> K
    H --> K

캡슐화 적용 사례:

1. Order Service 캡슐화:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class OrderService:
    def __init__(self):
        self._order_repository = OrderRepository()
        self._inventory_service = InventoryService()
        self._payment_service = PaymentService()
        self._notification_service = NotificationService()
    
    def create_order(self, user_id, items, payment_info):
        """주문 생성 - 복잡한 비즈니스 로직을 캡슐화"""
        try:
            # 1. 재고 확인 (내부 구현 숨김)
            if not self._validate_inventory(items):
                raise InsufficientStockError("재고 부족")
            
            # 2. 주문 생성 (내부 상태 관리)
            order = self._create_order_entity(user_id, items)
            
            # 3. 결제 처리 (외부 의존성 캡슐화)
            payment_result = self._process_payment(order, payment_info)
            
            # 4. 재고 차감 (트랜잭션 관리)
            self._reserve_inventory(items)
            
            # 5. 주문 저장 (데이터 접근 캡슐화)
            saved_order = self._order_repository.save(order)
            
            # 6. 알림 발송 (비동기 처리 캡슐화)
            self._send_notifications(saved_order)
            
            return OrderDTO.from_entity(saved_order)
            
        except Exception as e:
            self._rollback_transaction(order_id)
            raise OrderProcessingError(f"주문 처리 실패: {str(e)}")

Workflow:

sequenceDiagram
    participant Client
    participant OrderService
    participant InventoryService
    participant PaymentService
    participant Database
    participant NotificationService
    
    Client->>OrderService: create_order(user_id, items, payment_info)
    OrderService->>InventoryService: validate_inventory(items)
    InventoryService-->>OrderService: validation_result
    
    OrderService->>OrderService: create_order_entity()
    OrderService->>PaymentService: process_payment(order, payment_info)
    PaymentService-->>OrderService: payment_result
    
    OrderService->>InventoryService: reserve_inventory(items)
    OrderService->>Database: save(order)
    Database-->>OrderService: saved_order
    
    OrderService->>NotificationService: send_notifications(order)
    OrderService-->>Client: OrderDTO

캡슐화의 역할:

  • 복잡성 숨김: 주문 생성의 복잡한 과정을 단순한 메서드 호출로 추상화
  • 의존성 관리: 다양한 서비스 간의 복잡한 상호작용을 내부에서 처리
  • 오류 처리: 각 단계에서 발생할 수 있는 오류를 통합적으로 관리
  • 데이터 일관성: 트랜잭션 범위 내에서 데이터 무결성 보장

실무에서 효과적으로 적용하기 위한 고려사항 및 주의할 점

구분고려사항주의할 점권장사항
설계 단계적절한 추상화 수준 결정과도한 캡슐화로 인한 복잡성 증가도메인 전문가와 협업하여 비즈니스 로직 중심 설계
구현 단계일관된 명명 규칙 적용접근제어자 남용팀 내 코딩 컨벤션 수립 및 준수
성능 고려메서드 호출 오버헤드 최소화불필요한 Getter/Setter 남발성능 크리티컬한 부분은 직접 접근 고려
유지보수인터페이스 안정성 유지공개 API 빈번한 변경버전 관리 전략 수립
테스트Mock 객체 활용한 단위 테스트Private 메서드 테스트의 어려움행위 기반 테스트 집중
문서화공개 인터페이스 명확한 문서화내부 구현 세부사항 노출API 문서 자동 생성 도구 활용

실무에서 효과적으로 적용하기 위한 고려사항 및 주의할 점

캡슐화를 실무에 효과적으로 적용하기 위해서는 다음과 같은 사항을 고려해야 합니다:

고려사항설명권장 사항
접근 제한자의 적절한 사용데이터의 민감도에 따라 private, protected, public 등의 접근 제한자를 적절히 사용해야 합니다.민감한 데이터는 private 으로 선언하고, 필요한 경우에만 public 메서드를 통해 접근을 허용합니다.
Getter/Setter 메서드의 사용데이터에 대한 접근과 수정을 제어하기 위해 Getter 와 Setter 메서드를 사용합니다.데이터의 무결성을 유지하기 위해 Setter 메서드에서 유효성 검사를 수행합니다.
내부 구현의 변경 가능성 고려내부 구현이 변경되더라도 외부에 영향을 주지 않도록 설계해야 합니다.인터페이스를 안정적으로 유지하고, 내부 구현의 변경이 외부에 영향을 주지 않도록 합니다.
테스트 용이성 확보캡슐화된 클래스의 테스트를 용이하게 하기 위해 테스트 인터페이스를 제공하거나, 접근 제한을 완화할 수 있습니다.테스트를 위한 별도의 인터페이스를 제공하거나, 테스트 전용 빌드를 활용합니다.

실무에서 효과적으로 적용하기 위한 고려사항 및 주의할 점

고려사항설명권장사항
접근 제어 적절성과도한 공개는 데이터 노출 위험최소 권한 원칙 적용
인터페이스 명확성명확한 API 설계 필요문서화 및 표준화
테스트 용이성캡슐화로 인한 테스트 복잡성단위 테스트 및 Mock 활용

최적화하기 위한 고려사항 및 주의할 점

고려사항설명권장사항
오버헤드 최소화불필요한 접근자 호출 줄이기프로파일링 및 핫스팟 최적화
적절한 추상화 수준과도한 캡슐화 방지설계 리뷰 및 리팩토링

최적화하기 위한 고려사항 및 주의할 점

캡슐화를 최적화하기 위해서는 다음과 같은 사항을 고려해야 합니다:

고려사항설명권장 사항
성능 최적화Getter/Setter 메서드의 호출이 빈번한 경우, 성능에 영향을 줄 수 있습니다.필요한 경우, 직접 접근을 허용하거나, 캐싱 등의 기법을 활용하여 성능을 최적화합니다.
코드의 간결성 유지불필요한 Getter/Setter 메서드의 생성은 코드의 복잡성을 증가시킬 수 있습니다.실제로 외부에서 접근이 필요한 필드에 대해서만 Getter/Setter 메서드를 생성합니다.
유지보수성 향상내부 구현의 변경이 외부에 영향을 주지 않도록 설계하여 유지보수성을 향상시킵니다.인터페이스를 안정적으로 유지하고, 내부 구현의 변경이 외부에 영향을 주지 않도록 합니다.
보안 강화민감한 데이터에 대한 접근을 제한하여 보안을 강화합니다.민감한 데이터는 private 으로 선언하고, 필요한 경우에만 public 메서드를 통해 접근을 허용합니다.

최적화하기 위한 고려사항 및 주의할 점

구분최적화 방법주의사항권장사항
메모리 최적화불필요한 객체 생성 방지객체 풀링으로 인한 복잡성프로파일링 도구로 메모리 사용량 모니터링
성능 최적화인라인 메서드 활용캡슐화 원칙 위배 가능성컴파일러 최적화 우선 고려
네트워크 최적화DTO 패턴으로 데이터 전송 최적화과도한 DTO 객체 생성직렬화 효율성 고려한 DTO 설계
캐싱 최적화불변 객체로 안전한 캐싱캐시 무효화 복잡성캐시 정책과 라이프사이클 명확화
동시성 최적화Thread-safe 한 캡슐화 구현성능 저하 가능성읽기 전용 데이터와 가변 데이터 분리
확장성 최적화플러그인 아키텍처 적용인터페이스 설계의 복잡성확장 포인트 사전 식별 및 설계

기타 사항

캡슐화 관련 주요 문제들

1. 캡슐화 위반 (Encapsulation Violation)

문제 정의: 내부 구현 세부사항이 외부로 노출되거나 외부에서 직접 접근되는 문제

원인:

  • 부적절한 접근제어자 사용
  • 내부 객체의 참조를 직접 반환
  • public 필드 노출
  • 너무 많은 Getter/Setter 제공

영향:

  • 데이터 무결성 손상
  • 의존성 증가로 인한 유지보수 어려움
  • 보안 취약점 발생
  • 코드 변경 시 연쇄적 영향

탐지 및 진단:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 문제가 있는 코드 예시
class BadEncapsulation:
    def __init__(self):
        self.important_data = []  # public 필드
    
    def get_data(self):
        return self.important_data  # 직접 참조 반환

# 진단 방법
import ast
import inspect

def analyze_encapsulation_violations(cls):
    """캡슐화 위반 사항 분석"""
    violations = []
    
    # 1. public 필드 검사
    for attr_name in dir(cls):
        if not attr_name.startswith('_') and not callable(getattr(cls, attr_name)):
            violations.append(f"Public 필드 발견: {attr_name}")
    
    # 2. 메서드 시그니처 분석
    for method_name, method in inspect.getmembers(cls, predicate=inspect.ismethod):
        if method_name.startswith('get_') and not method_name.startswith('_'):
            violations.append(f"잠재적 캡슐화 위반 메서드: {method_name}")
    
    return violations

예방 방법:

  • 모든 데이터 필드를 private 으로 선언
  • 방어적 복사 (Defensive Copy) 사용
  • 불변 객체 활용
  • 정기적인 코드 리뷰

해결 방법 및 기법:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 개선된 캡슐화 구현
class GoodEncapsulation:
    def __init__(self):
        self._important_data = []  # private 필드
    
    def get_data_copy(self):
        return self._important_data.copy()  # 방어적 복사
    
    def add_data(self, item):
        if self._validate_item(item):
            self._important_data.append(item)
    
    def _validate_item(self, item):  # private 메서드
        return item is not None and len(str(item)) > 0

2. 과도한 접근자 메서드 (Excessive Accessor Methods)

문제 정의: 모든 private 필드에 대해 무분별하게 Getter/Setter 를 제공하는 안티패턴

원인:

  • " 모든 필드에 접근자가 필요하다 " 는 잘못된 인식
  • IDE 의 자동 생성 기능 남용
  • 객체지향 설계 원칙에 대한 이해 부족

해결 방법:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 문제가 있는 코드
class OverAccessors:
    def __init__(self):
        self._name = ""
        self._age = 0
        self._email = ""
    
    # 모든 필드에 대한 Getter/Setter (불필요함)
    def get_name(self): return self._name
    def set_name(self, name): self._name = name
    # … 모든 필드에 대해 반복

# 개선된 코드 - Tell, Don't Ask 원칙 적용
class BetterDesign:
    def __init__(self, name, age, email):
        self._name = name
        self._age = age
        self._email = email
    
    def introduce_yourself(self):
        """객체에게 행동을 요청"""
        return f"안녕하세요, {self._name}입니다. {self._age}세입니다."
    
    def send_welcome_email(self):
        """객체가 자신의 데이터를 활용해 행동"""
        return f"{self._email}로 환영 메일을 발송했습니다."
    
    @property
    def name(self):  # 꼭 필요한 경우만 읽기 전용으로 제공
        return self._name

3. 상속과 캡슐화의 충돌

문제 정의: 상속 관계에서 부모 클래스의 캡슐화가 깨지거나 protected 멤버 오남용

해결 방법:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 컴포지션을 활용한 해결
class Engine:
    def __init__(self):
        self._power = 100
        self._fuel_level = 50
    
    def start(self):
        if self._fuel_level > 0:
            return "엔진 시동"
        return "연료 부족"
    
    def get_status(self):
        return {"power": self._power, "fuel": self._fuel_level}

class Car:
    def __init__(self):
        self._engine = Engine()  # 상속 대신 컴포지션 사용
        self._speed = 0
    
    def start_car(self):
        result = self._engine.start()
        if "시동" in result:
            return "차량 시동 완료"
        return "시동 실패: " + result
    
    def get_engine_status(self):
        return self._engine.get_status()  # 위임을 통한 접근

4. 멀티스레드 환경에서의 캡슐화 문제

해결 방법:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import threading
from contextlib import contextmanager

class ThreadSafeBankAccount:
    def __init__(self, initial_balance=0):
        self._balance = initial_balance
        self._lock = threading.RLock()  # 재진입 가능한 락
    
    @contextmanager
    def _thread_safe_operation(self):
        """스레드 안전 연산을 위한 컨텍스트 매니저"""
        self._lock.acquire()
        try:
            yield
        finally:
            self._lock.release()
    
    def deposit(self, amount):
        with self._thread_safe_operation():
            if amount > 0:
                self._balance += amount
                return True
        return False
    
    def withdraw(self, amount):
        with self._thread_safe_operation():
            if 0 < amount <= self._balance:
                self._balance -= amount
                return True
        return False
    
    @property
    def balance(self):
        with self._thread_safe_operation():
            return self._balance

기타 사항

캡슐화와 관련하여 발생할 수 있는 문제와 그 해결 방법은 다음과 같습니다:

문제원인영향탐지 및 진단예방 방법해결 방법 및 기법
Getter/Setter 의 남용모든 필드에 대해 무분별하게 생성코드 복잡도 증가, 유지보수 어려움리팩토링 도구로 반복 코드 탐지필요한 경우에만 생성리팩토링 도구 사용 및 인터페이스 명세 활용
과도한 캡슐화로 테스트 어려움private 필드 및 메서드의 접근 불가테스트 커버리지 낮음커버리지 분석 툴 사용테스트 가능한 구조 설계패키지 접근자 활용 또는 테스트 전용 빌드 구성
캡슐화가 코드 성능에 미치는 영향메서드 호출 과다, 객체 생성 비용 증가성능 저하프로파일링 도구단순 구조 유지, 인라인 처리JIT(Just-In-Time) 컴파일러 최적화 활용

기타 사항

문제원인영향탐지/진단예방 방법해결 방법
과도한 공개접근 제한자 미사용/부적절데이터 노출, 무결성 훼손코드 리뷰, 보안 감사접근 제한자 사용, 코드 리뷰접근 제한자 강화, 리팩토링
불충분한 은닉내부 데이터 직접 노출객체 무결성 손상정적 분석, 테스트캡슐화 원칙 준수리팩토링, 접근자 메서드 도입
복잡한 인터페이스지나친 getter/setter 남용코드 복잡성 증가코드 리뷰, 정적 분석인터페이스 단순화, 리팩토링
성능 저하과도한 접근자 호출실행 속도 저하프로파일링핫스팟 최적화, 캐싱 적용

주제와 관련하여 주목할 내용

주제항목설명
정보 은닉접근 제한자내부 데이터 보호, 무결성 유지
인터페이스명확한 API외부와의 상호작용을 단순화
테스트단위 테스트캡슐화 구조의 테스트 전략
설계 원칙최소 권한 원칙불필요한 공개 방지, 보안 강화
리팩토링코드 단순화불필요한 getter/setter 제거, 최적화

주제와 관련하여 주목할 내용

주제항목설명
설계 원칙정보 은닉 (Information Hiding)캡슐화는 정보 은닉의 실질적 구현 방식으로, 소프트웨어 모듈의 경계를 명확히 함
SOLID 원칙단일 책임 원칙 (SRP)하나의 클래스나 모듈은 오직 하나의 변경 이유만 가져야 함–캡슐화로 SRP 준수 용이
접근 제한자최소 권한 원칙 (Principle of Least Privilege)외부 접근을 최소화하여 보안성과 안정성을 확보
언어 기능Properties (Python, C# 등)Getter/Setter 메서드를 대체할 수 있는 문법적 캡슐화 도구
보안민감 정보 보호암호화, 토큰 등과 결합하여 사용 시 정보 보안에 효과적

주제와 관련하여 주목할 내용

주제항목설명
현대적 접근함수형 프로그래밍에서의 캡슐화불변성과 클로저를 통한 캡슐화 구현
마이크로서비스 아키텍처서비스 단위의 캡슐화와 API 경계
언어별 특징Python 의 Property 데코레이터간결한 Getter/Setter 구현 방식
JavaScript 의 Private FieldsES2022 의 # 문법을 통한 진정한 private
C#의 Auto-Property자동 속성을 통한 간편한 캡슐화
디자인 패턴파사드 패턴 (Facade Pattern)복잡한 하위 시스템을 간단한 인터페이스로 캡슐화
프록시 패턴 (Proxy Pattern)객체 접근을 제어하는 캡슐화 방식
어댑터 패턴 (Adapter Pattern)호환되지 않는 인터페이스를 캡슐화하여 통합
아키텍처레이어드 아키텍처계층별 관심사 분리를 통한 캡슐화
헥사고날 아키텍처포트와 어댑터를 통한 비즈니스 로직 캡슐화
보안 측면접근 제어 (Access Control)역할 기반 접근 제어와 캡슐화의 결합
데이터 암호화민감한 데이터의 캡슐화된 보호
성능 최적화지연 로딩 (Lazy Loading)필요시점까지 객체 생성을 지연하는 캡슐화
객체 풀링 (Object Pooling)객체 생성 비용을 캡슐화하여 최적화

추가 학습 내용

카테고리간략한 설명주제
고급 OOP 개념캡슐화와 연계된 고급 객체지향 개념들추상화, 상속, 다형성과의 상호작용
디자인 패턴캡슐화를 활용하는 다양한 설계 패턴들GoF 패턴, 엔터프라이즈 패턴
아키텍처 패턴대규모 시스템에서의 캡슐화 적용마이크로서비스, 서버리스, 이벤트 드리븐
함수형 프로그래밍다른 패러다임에서의 캡슐화 개념불변성, 클로저, 모나드
보안 엔지니어링보안 관점에서의 캡슐화 활용접근 제어, 데이터 보호, 암호화
성능 엔지니어링고성능 시스템에서의 캡슐화 최적화메모리 관리, 캐싱 전략, 병렬 처리
테스트 전략캡슐화된 코드의 효과적인 테스트 방법단위 테스트, 모킹, TDD
API 설계외부 인터페이스 설계와 캡슐화RESTful API, GraphQL, gRPC
도메인 주도 설계비즈니스 도메인 중심의 캡슐화애그리게이트, 바운디드 컨텍스트
클린 아키텍처클린 코드와 아키텍처에서의 캡슐화의존성 역전, 관심사 분리

추가로 학습해야 할 내용

카테고리간략한 설명주제
객체 지향 설계캡슐화 외의 다른 OOP 원칙들과의 연계성추상화, 상속, 다형성
디자인 패턴캡슐화를 활용하는 대표적인 패턴 학습팩토리 패턴, 빌더 패턴 등
테스트 전략캡슐화된 클래스를 효율적으로 테스트하는 기법접근성 제어, 테스트 전용 인터페이스
성능 최적화캡슐화 구조에서 성능을 향상시키는 방법인라인, 캐싱, 접근자 최적화
언어별 구현 방식캡슐화가 언어별로 어떻게 구현되는지 비교Python vs Java vs JavaScript

추가로 학습해야 할 내용

카테고리간략한 설명주제
디자인 패턴캡슐화와 연계된 설계 패턴프록시, 데코레이터, 파사드
SOLID 원칙캡슐화와 관련된 설계 원칙단일 책임, 인터페이스 분리
테스트 기법캡슐화 구조의 테스트 방법Mock, 단위 테스트
리팩토링불필요한 getter/setter 제거코드 리뷰, 핫스팟 분석

용어 정리

카테고리용어설명
OOP캡슐화 (Encapsulation)데이터와 메서드를 하나로 묶고 외부에서 직접 접근하지 못하도록 보호하는 원리
OOP정보 은닉 (Information Hiding)내부 구현을 감추고 외부에 필요한 인터페이스만 제공하는 원리
OOP접근 제한자 (Access Modifier)private, protected, public 등 접근 범위 제어 키워드
OOPgetter/setter속성 접근 및 변경을 위한 메서드
OOP프로퍼티 (property)속성 접근을 메서드처럼 처리하는 기능 (Python 등)
OOP인터페이스 (interface)외부에 노출할 기능 정의 및 구현 분리 구조

용어 정리

카테고리용어설명
개념캡슐화 (Encapsulation)데이터와 메서드를 하나의 단위로 묶고, 외부로부터의 직접적인 접근을 제한하여 시스템의 복잡성을 관리하고 보안을 강화하는 객체 지향 프로그래밍의 핵심 원칙
개념정보 은닉 (Information Hiding)내부 구현 세부 사항을 숨기고, 외부에는 명확한 인터페이스만을 제공하여 시스템의 안정성과 보안을 강화하는 설계 원칙
개념접근 제한자 (Access Modifier)데이터나 메서드의 접근 범위를 정의하는 키워드로, private, protected, public 등이 있음
개념Getter/Setter 메서드데이터에 대한 접근과 수정을 제어하기 위해 사용하는 메서드로, 데이터의 무결성을 유지하고 외부로부터의 직접적인 접근을 제한함

용어 정리

카테고리용어설명
객체지향 원칙캡슐화 (Encapsulation)데이터와 메서드를 하나의 단위로 묶고 외부 접근을 제한
객체지향 원칙정보 은닉 (Information Hiding)객체의 내부 세부사항을 외부로부터 숨기는 설계 원칙
객체지향 원칙접근 제한자 (Access Modifier)변수나 메서드에 대한 접근 범위를 지정하는 키워드
언어 기능Getter / Setterprivate 필드에 간접적으로 접근하기 위한 공개 메서드
설계 원칙최소 권한 원칙필요한 최소한의 권한만을 부여하여 보안 강화

용어 정리

카테고리용어설명
기본 개념접근제어자 (Access Modifier)클래스 멤버의 접근 권한을 제어하는 키워드 (public, private, protected)
정보 은닉 (Information Hiding)객체의 내부 구현을 외부로부터 숨기는 프로그래밍 기법
캡슐 (Capsule)데이터와 메서드를 하나로 묶는 보호 단위
모듈화 (Modularization)시스템을 독립적인 모듈로 분리하여 설계하는 방법
설계 원칙Tell, Don’t Ask객체의 데이터를 요청하지 말고 행동을 요청하라는 설계 원칙
결합도 (Coupling)모듈 간의 의존성 정도를 나타내는 지표
응집도 (Cohesion)모듈 내부 요소들 간의 관련성 정도
단일 책임 원칙 (SRP)클래스는 하나의 책임만 가져야 한다는 원칙
구현 기법Getter/Setterprivate 필드에 대한 접근을 제공하는 메서드 쌍
방어적 복사 (Defensive Copy)내부 객체의 복사본을 반환하여 외부 수정을 방지하는 기법
불변 객체 (Immutable Object)생성 후 상태가 변경되지 않는 객체
프로퍼티 (Property)필드처럼 사용되지만 메서드로 구현된 클래스 멤버
디자인 패턴파사드 패턴 (Facade Pattern)복잡한 하위 시스템을 간단한 인터페이스로 캡슐화하는 패턴
프록시 패턴 (Proxy Pattern)다른 객체에 대한 접근을 제어하는 대리자 객체를 제공하는 패턴
팩토리 패턴 (Factory Pattern)객체 생성 로직을 캡슐화하는 생성 패턴
전략 패턴 (Strategy Pattern)알고리즘을 캡슐화하여 교체 가능하게 만드는 패턴
아키텍처레이어드 아키텍처 (Layered Architecture)시스템을 계층으로 나누어 관심사를 분리하는 아키텍처
마이크로서비스 (Microservices)독립적으로 배포 가능한 서비스 단위로 시스템을 분할하는 아키텍처
API 게이트웨이 (API Gateway)여러 마이크로서비스에 대한 단일 진입점을 제공하는 구성요소
바운디드 컨텍스트 (Bounded Context)도메인 주도 설계에서 모델의 경계를 정의하는 개념
보안접근 제어 목록 (ACL)리소스에 대한 접근 권한을 정의하는 목록
역할 기반 접근 제어 (RBAC)사용자의 역할에 따라 접근 권한을 부여하는 보안 모델
데이터 마스킹 (Data Masking)민감한 데이터를 숨기거나 변조하여 보호하는 기법
암호화 (Encryption)데이터를 읽을 수 없는 형태로 변환하는 보안 기법
성능 최적화지연 로딩 (Lazy Loading)필요할 때까지 객체 생성이나 데이터 로딩을 지연하는 기법
캐싱 (Caching)자주 사용되는 데이터를 임시 저장하여 성능을 향상시키는 기법
객체 풀링 (Object Pooling)객체를 미리 생성하여 재사용함으로써 생성 비용을 절약하는 기법
인라인 함수 (Inline Function)함수 호출 오버헤드를 줄이기 위해 함수 내용을 호출 지점에 직접 삽입하는 최적화
테스트단위 테스트 (Unit Test)개별 모듈이나 컴포넌트를 독립적으로 테스트하는 방법
모킹 (Mocking)테스트 시 실제 객체 대신 가짜 객체를 사용하는 기법
의존성 주입 (Dependency Injection)객체의 의존성을 외부에서 주입하여 결합도를 낮추는 패턴
테스트 더블 (Test Double)테스트 목적으로 실제 객체를 대체하는 가짜 객체의 총칭

참고 및 출처

학술 문헌 및 서적

온라인 문서 및 튜토리얼

아키텍처 및 설계 문서

연구 논문 및 학술 자료

실무 가이드 및 베스트 프랙티스

도구 및 프레임워크 문서

커뮤니티 및 포럼

비디오 강의 및 온라인 코스

업계 블로그 및 기술 문서

참고 및 출처

참고 및 출처

참고 및 출처


캡슐화 (Encapsulation) 종합 분석

캡슐화는 데이터와 그 데이터를 처리하는 메서드를 하나의 단위로 묶고, 외부로부터 접근을 제한하는 것을 의미한다.
이는 마치 약캡슐이 내용물을 보호하고 외부와의 상호작용을 제한하는 것과 유사하다.

실제 코드로 보면 다음과 같다:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class BankAccount:
    def __init__(self):
        self.__balance = 0  # private 변수
        self._transaction_count = 0  # protected 변수
        
    def deposit(self, amount):
        """입금 메서드"""
        if amount > 0:
            self.__balance += amount
            self._transaction_count += 1
            return True
        return False
    
    def withdraw(self, amount):
        """출금 메서드"""
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            self._transaction_count += 1
            return True
        return False
    
    def get_balance(self):
        """잔액 조회 메서드"""
        return self.__balance

캡슐화의 주요 특징과 장점

데이터 은닉

객체의 내부 상태를 외부에서 직접 접근하지 못하도록 한다. 이는 주로 private 접근 제어자를 사용하여 구현된다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Employee:  
	def __init__(self, name, salary):  
		self.__name = name # private  
		self.__salary = salary # private
		
	def get_name(self):
		return self.__name
		
	def get_salary(self):
		return self.__salary
		
	def give_raise(self, amount):
		if amount > 0:
			self.__salary += amount
인터페이스 제공

객체의 상태를 변경하거나 조회할 때는 public 메서드를 통해 접근한다. 이를 통해 객체의 내부 구현을 숨기고 필요한 기능만을 외부에 노출한다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Database:
    def __init__(self, connection_string):
        self.__connection = self.__connect(connection_string)
        
    def __connect(self, connection_string):
        """데이터베이스 연결 (구현 세부사항 숨김)"""
        # 연결 로직 구현
        pass
        
    def execute_query(self, query):
        """공개 인터페이스"""
        self.__validate_query(query)
        return self.__connection.execute(query)
        
    def __validate_query(self, query):
        """쿼리 유효성 검사 (내부 구현)"""
        # 검증 로직 구현
        pass
유지보수성 향상

내부 구현을 변경하더라도 외부 인터페이스가 변경되지 않으면, 다른 코드에 영향을 미치지 않는다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class ShoppingCart:
    def __init__(self):
        self.__items = []
        self.__total = 0
        
    def add_item(self, item):
        """아이템 추가"""
        self.__items.append(item)
        self.__update_total()
        
    def remove_item(self, item):
        """아이템 제거"""
        if item in self.__items:
            self.__items.remove(item)
            self.__update_total()
            
    def __update_total(self):
        """총액 업데이트 (내부 구현 변경 가능)"""
        self.__total = sum(item.price for item in self.__items)
코드의 안정성

객체의 상태를 직접 변경할 수 없으므로, 의도치 않은 상태 변경을 방지할 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Product:  
	def __init__(self, name, price):  
		self._name = name # protected  
		self.__price = price # private  
		self.id = None # public
		
	@property
	def price(self):
		"""가격 조회를 위한 프로퍼티"""
		return self.__price
		
	@price.setter
	def price(self, new_price):
		"""가격 설정을 위한 프로퍼티"""
		if new_price > 0:
			self.__price = new_price
모듈화

관련된 데이터와 기능을 하나의 단위로 묶어 코드의 구조를 개선한다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class GameCharacter:
    def __init__(self, name):
        self.__name = name
        self.__health = 100
        self.__experience = 0
        
    def take_damage(self, amount):
        """데미지 처리"""
        self.__health = max(0, self.__health - amount)
        self.__check_status()
        
    def gain_experience(self, amount):
        """경험치 획득"""
        self.__experience += amount
        self.__level_up_check()
        
    def __check_status(self):
        """상태 확인 (내부 로직)"""
        if self.__health == 0:
            self.__handle_death()
            
    def __handle_death(self):
        """사망 처리 (내부 로직)"""
        # 사망 관련 로직 구현
        pass

캡슐화를 통한 객체 설계 원칙

  1. 최소 권한의 원칙:
    객체의 속성과 메서드는 가능한 한 최소한의 접근 권한만을 가져야 한다.

  2. 인터페이스와 구현의 분리:
    공개 인터페이스는 안정적으로 유지하면서, 내부 구현은 자유롭게 변경할 수 있어야 한다.

  3. 데이터 무결성 보장:
    객체의 상태는 해당 객체의 메서드를 통해서만 변경되어야 한다.


용어 정리

용어설명

참고 및 출처