Yomni's TIL Help

아이템 15. 클래스와 멤버의 접근 권한을 최소화 하라

1. 정보은닉(Information Hiding) 과 캡슐화(Encapsulation)의 중요성

  • 정보 은닉은 내부 구현을 숨기고 외부에서 접근할 수 없도록 제한하는 개념이다.

  • 캡슐화는 객체의 상태를 외부에서 직접 변경하지 못하도록 하고, 필요한 경우에만 공개하는 설계 원칙이다.

  • 접근 제한을 통해 코드의 유지보수성을 높이고, 오류 발생 가능성을 줄이며, 보안성을 강화할 수 있다.

2. 접근 수준(Access Level)과 사용 원칙

자바에서는 네 가지 접근 수준을 제공하며, 가장 제한적인 수준부터 적용하는 것이 좋다.

접근 수준

적용 대상

같은 클래스

같은 패키지

자식 클래스

전체 접근

private

클래스 내부

O

X

X

X

package-private(기본 접근제어자)

같은 패키지 내에서만 접근 가능

O

O

X

X

protected

같은 패키지 + 상속 관계에서 접근 가능

O

O

O

X

public

어디서든 접근 가능

O

O

O

O

설계 원칙

  1. 가장 제한적인 접근 수준부터 적용하고, 꼭 필요한 경우에만 공개한다.

  • private --> public 순서

  1. 클래스 자체를 public 으로 만들지 않는 것이 좋다.

  • 만약 특정 클래스를 라이브러리 사용자에게 공개할 필요가 없다면, package-private 로 설정하여 내부 구현을 감출 수 있다.

3. 멤버(필드 및 메서드) 접근 제어

  1. 필드는 private 으로 선언하고, 필요하면 접근자(getter)를 제공한다.

    • 클래스 내부 데이터를 직접 노출하지 말고, 접근 메서드를 통해 제공해야 한다.

class Person { private String name; // 직접 접근 불가능 public String getName() { // 필요할 때만 접근자 제공 return name; } }
  • 필드를 public 으로 선언하면 객체의 내부 표현이 외부 API 에 노출되므로, 유지보수가 어려워 질 수 있다.

  1. 불변 필드(final)의 경우, public 으로 공개해도 괜찮다.

    • 불변 객체는 상태가 변경되지 않으므로 public final 로 공개해도 안전하다.

public class Constants { public static final int MAX_SIZE = 100; // 변경 불가능하므로 공개해도 문제 없음 }
  • 하지만 가변 객체(List, Map) 를 public static final 로 공개하면 내부 상태가 변경될 위험이 있다.

  1. 배열 필드는 private 으로 선언하고, 복사본을 반환한다.

public class Security { private final String[] values = {"A", "B", "C"}; public String[] getValues() { return values.clone(); // 원본 배열을 보호하기 위해 복사본 제공 } }
  • 배열을 public 으로 직접 노출하면 외부에서 배열 내용을 변경할 수 있어 보안상 취약하다.

4. 패키지 프라이빗(package-private) 클래스 활용

  • 내부 구현 클래스는 public 으로 만들지 말고, package-private 으로 설정하는 것이 좋다.

  • 라이브러리를 만들 때, 내부에서만 사용하는 클래스는 package-private 으로 숨길 수 있다.

// 내부 구현 클래스를 package-private으로 유지 class InternalHelper { static void doSomething() { System.out.println("Internal processing..."); } }
  • 이렇게 하면 외부에서는 InternalHelper 클래스를 사용할 수 없으므로 내부 구현이 보호된다.

5. 상속을 고려한 접근제어 (protected 사용 주의)

  • protected 는 같은 패키지의 다른 클래스에서 접근이 가능하므로,


    상속용이 아닌 클래스에서는 protected를 사용할 필요가 거의 없다.

  • 상속을 허용하려면 설계상 의도가 분명해야 하며, 무분별한 protected 사용은 지양해야 한다.

6. 결론

  • 모든 클래스와 멤버의 접근 수준을 가능한 한 제한해야 한다.

  • 클래스의 필드는 private로 선언하고, 직접 노출을 피해야 한다.

  • 불변 필드(final)는 public으로 공개할 수 있지만, 가변 객체는 반드시 보호해야 한다.

  • 내부 구현 클래스는 package-private으로 유지하여 외부 노출을 방지해야 한다.

  • protected는 신중하게 사용하고, 상속이 정말 필요한 경우에만 활용해야 한다.

부록 ; 느낀점

  • 정보은닉, 캡슐화의 설명은 대부분 추상적이지만, 객체지향을 제대로 접목시키면 그 이점이 특히 두드러지게 나타난다.

    • 특히 유지보수성이 높아진다는 이점이 가장 크게 와닿았던 것 같다.

  • 상속을 허용하려면 설계상 의도가 분명해야 한다는 점에서 상속 자체를 개인적으론 지양해야 된다는 생각도 있다.

    • 상속 관계의 객체끼리 지나치게 의존도가 높아지기 때문에, '역할'을 고려한 설계가 아니라면 상속은 되도록 지양해야 한다.

Last modified: 19 March 2025