티스토리 뷰

* 이펙티브 자바 2/E를 읽고 공부하기 위해 기록한 게시글입니다.

 

13. 클래스와 멤버의 접근 권한은 최소화하라

잘 설계된 모듈과 그렇지 못한 모듈을 구별짓는 가장 중요한 속성 중 하나는, 모듈 내부의 데이터를 비롯한 구현 세부사항을 다른 모듈에게 잘 감추느냐의 여부이다

- 잘 설계된 모듈은 구현 세부사항을 전부 API 뒤에 감춘다. 모듈들은 서로 API를 통해서만 통신하며, 각자 내부적으로는 무슨 일을 하는지 신경 쓸 필요가없다. (캡슐화, 은닉화) -- 소프트웨어 설계의 기본 원칙.

 

정보 은닉이 중요한 이유는 정보 은닉이 시스템을 구성하는 모듈 사이의 의존성을 낮춰서 각자 개별적으로 개발/시험/최적화/이해/변경이 가능하도록 해주기 때문이다. 병렬적 개발을 가능하게 만들어 주고, 시스템이 완성된 다음 어떤 모듈이 성능 문제를 일으키는지 프로파일링 하기 용이하게 해준다.

또한 소프트웨어의 재사용성을 높인다. 모듈간 의존성이 낮으므로 각 모듈은 다른 소프트웨어를 개발하는데에도 사용되어질 수 있어 대규모 시스템 개발 과정의 위험성도 낮출 수 있다. 그냥 최고다.

 

이렇게 좋은 정보 은닉을 자바는 어떤 방법을 통해 가능하게 하는 것일까?

-> 접근 제어 매커니즘을 이용해 클래스와 인터페이스, 그 멤버들의 접근 권한을 규정한다. 

--> 어떤 개체의 접근 권한은 해당 개체가 선언된 위치 및 권한 수정자(접근 제한자 - public, protected, private)에 의해 결정된다. 접근 제한자의 적절한 사용이 정보 은닉 원칙을 실현하는 핵심 역할이다.

 

 

정보 은닉을 실현하는 가장 기본적인 원칙은

"각 클래스와 멤버는 가능한 한 접근 불가능하도록 만들어라"

 

 

(정상적인 동작을 보증하는 한도 내에서 가장 낮은 접근 권한을 설정해라)

최상위 레벨(중첩되지 않은) 클래스와 인터페이스에 부여할 수 있는 접근권한은 default와 public 두 가지.

public을 붙이면 해당 개체는 전역적 개체가 되고, default를 붙이면 해당 패키지 안에서만 유효한 개체가 된다.

- 최상위 레벨 클래스나 인터페이스는 가능한 한 default로 선언해야 한다.

-> default로 선언하면 API의 일부가 아니라 구현 세부사항에 속하게 되므로 클라이언트 코드를 변경하지 않고도 자유롭게 변경/삭제/대체할 수 있기 때문이다. 만약 public으로 선언했다면 호환성을 보장하기 위해 해당 개체를 계속 지원 해야함.

 

 

만약 default로 선언된 최상위 레벨 클래스나 인터페이스를 사용하는 사용자 클래스가 단 하나 뿐이라면, 해당 최상위 레벨 클래스를 사용자 클래스의 private 중첩 클래스로 합쳐서 만드는 것을 고려해라. (내부 클래스로 집어넣어라)

- 패키지 전체가 아니라 단 하나의 클래스만이 해당 클래스의 접근 권한을 갖게 된다

 

 

public API 클래스를 설계한 뒤에는 다른 모든 멤버를 private로 선언하는 것이 바람직하다

- 같은 패키지 내의 다른 클래스가 반드시 사용해야 하는 멤버인 경우에는 private 대신 default(혹은 생략)로 만들어줄 수는 있다. 다만 이런 작업이 빈번한 경우 시스템 설계를 재검토 하여 클래스 간 의존성을 끊어낼 방법을 따져보는 것이 좋다.

- public 클래스의 멤버를 protected로 선언하는 경우, 멤버를 사용할 수 있는 범위가 엄청나게 증가한다(하위 클래스 추가). protected로 선언된 멤버는 해당 클래스의 공개 API와 같으며 영원히 유지해야 한다. 사실상 public이기 때문에 protected 사용도 자제하는 것이 좋겠다.

 

 

* 상위 클래스의 메서드를 재정의 할 때에는 원래 메서드의 접근권한보다 낮은 권한을 설정할 수 없다.

- 상위 클래스 객체를 사용할 수 있는 곳에서는 하위 클래스 객체도 사용할 수 있어야 하기 때문.

-> 특정한 인터페이스를 구현하는 클래스를 만들 때에는 인터페이스에 속한 메서드를 모두 해당 클래스의 public 메서드로 로 선언해야 한다 (원래 인터페이스의 모든 메서드는 public이다)

 

* 객체 필드(인스턴스 변수)는 되도록 public으로 선언하면 안된다.

- 비-final 필드나 변경 가능 객체에 대한 final 참조 필드를 public으로 선언하면, 필드에 저장될 값을 제한할 수 없게 된다. (메서드를 통하지 않고서도 변경이 가능해진다) 

-> 그 필드에 관계된 불변식을 강제할 수 없다.

- 변경 가능 public 필드를 가진 클래스는 다중 스레드 환경에서 안전하지 않다.

 

위 내용은 static 필드에도 적용되지만, 예외사항이 있다

- static final, 상수의 경우에는 public을 통해 외부에 공개해도 문제가 없다.

- 상수의 경우에는 반드시 기본 자료형 값을 갖거나, 변경 불가능 객체를 참조해야 한다.

 

 

* 길이가 0이 아닌 배열은 언제나 변경 가능하기 때문에 배열을 상수로 정의하거나, 배열 필드를 반환하는 접근자(Getter)를 정의하면 안된다. 보안 문제를 초래할 수 있음. 굳이 필요하다면 아래와 같은 방법을 사용.

    private static final String[] PRIVATE_VALUES = {...}; // 외부 접근 불가
    public static String[] values() {
        return PRIVATE_VALUES.clone(); // 복사된 배열을 반환
    }

 

 

(결론)

1. 접근 권한은 가능한 한 낮춰라

2. 최소한의 public API를 설계한 다음 모든 클래스, 인터페이스, 멤버는 API에서 제외해라.

3. public static final 필드를 제외한 어떤 필드도 (웬만하면) public 필드로 선언하지 마라.

4. public static final 필드가 참조하는 객체는 변경 불가능 객체로 만들어라.

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함