NMP-Study / EffectiveJava2022

Effective Java Study 2022
5 stars 0 forks source link

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

Closed okhee closed 2 years ago

KimYunsang-v commented 2 years ago

어설프게 설계된 컴포넌트와 잘 설계된 컴포넌트의 가장 큰 차이

정보은닉(information hiding) 또는 캡슐화(encapsulation)

정보은닉 또는 캡슐화를 사용하는 이유

  1. 정보은닉은 시스템을 구성하는 컴포넌트 사이의 결합도 또는 의존성을 낮춘다 (decouple)
  2. 구현 코드를 외부에서 변경 불가하게 하므로, 해당 기능을 변경해야 하는 상황이 발생할 경우 특정 클래스로만 변화가 수렴된다. (즉, 요구사항 변화에 따른 코드 수정 범위를 최소화)
    • 개발 속도 UP
    • 각각의 컴포넌트를 병렬적으로 개발할 수 있다
    • 관리 비용 down
    • 컴포넌트 각각에 대한 이해가 빨라지고, 다른 컴포넌트에 영향 끼칠 걱정없이 디버깅 진행이 가능하다.
    • 성능 최적화 UP
    • 시스템이 다 완성된 다음, 어떤 컴포넌트가 문제를 일으키는지 프로파일링하기에 좋다.
    • 재사용성 UP
    • 컴포넌트간 의존성이 낮으므로, 각 컴포넌트은 다른 소프트웨어 개발에도 사용 가능하다.
    • 큰 시스템 개발시 위험 부담 Down
    • 시스템 전체가 덜 되었더라도 각 모듈 별 성공 여부를 입증할 수 있음

정보 은닉을 위한 접근 제어(Access Modifier) 메커니즘

자바는 정보 은닉을 위한 장치로 접근 제어 메커니즘을 사용하는데 이 접근 제한자를 잘 사용하는 것이 정보 은닉의 핵심! (이 장의 핵심)

  1. 적용 문법

    • class 선언구 : public or package-private 만 가능 (protected 나 private는 올 수 없음)
    • 변수, 생성자, 메소드 선언구 : 4가지 다 적용 가능
  2. 종류 및 용도 image

키워드 class subclass package world 설명
private O       동일클래스
package-private (=default =friendly) O   O   동일클래스, 동일패키지의 (다른/하위)클래스
protected O O O   동일클래스, 동일패키지의 (다른/하위)클래스, 다른 패키지의 하위클래스
public O O O O 동일클래스, 동일패키지의 (다른/하위)클래스, 다른 패키지의 하위클래스, 다른 패키지의 다른 클래스

그래서 잘 설계된 컴포넌트를 만들려면 어떻게?

  1. 모든 클래스와 멤버의 접근성을 가능한 한 좁히자

    • 최상위 레벨 클래스나 인터페이스는 가능한 package-private로 선언
      • public으로 선언하게 되면 호환성을 보장하기 위해 해당 개체를 계속 지원해야된다
    • package-private로 선언된 최상위 클래스나 인터페이스를 사용하는 클래스(사용자 클래스)가 하나뿐이라면 사용자 클래스의 private static 중첩 클래스로 고려 (inner class or interface)
    • 필드나 메서드, 중첩 클래스(nested class), 중첩 인터페이스(neseted interface) 같은 멤버의 접근 권한은 최대한 private (꼭 다른 클래스가 사용해야 하는 경우만 package-private)
    • public 클래스의 멤버들은 protected 사용을 자제(최대한 package-private)
      • 공개 API일수록 영원히 지원돼야 하기 때문 (또는 내부 동작 방식을 API 문서에 적어 사용자에게 공개해야할 수 있음)
  2. 객체 필드(instance field)는 절대로 public으로 선언하면 안된다

    • 인스턴스 필드가 final이 아니거나 또는 가변 객체의 final 참조일 때 그 필드를 public으로 지정하면 외부에서 이 필드의 값을 임의로 변경 가능하므로 그 필드가 갖는 값을 제한 할 수 없게 된다.
      • 그 필드를 포함하는 상수식을 사용할 수 없게 된다는 말
    • 또한, 변경 가능 public 필드를 가진 클래스는 다중 스레드에 안전하지 않다
      • 필드의 값이 변경될 때 어떤 조치도 취할 수 없음
  3. 요소가 하나라도 있는 배열은 항상 가변적이라는 것에 주의하자.

    • 이런 경우 반드시 기본 자료형 값들을 갖거나, 변경 불가능 객체를 참조
    • public static final 배열 필드를 두거나, 배열 필드를 반환하는 접근자(accssor)를 정의하면 안된다(길이가 0이 아닌 배열은 언제나 변경가능)
class Main {
         // 보안 문제를 초래할 수 있는 코드
    public static final Integer[] VALUES = {1 , 2, 3 };
}

class Test{

    public static void main(String [] args){

        System.out.println(Main.VALUES[0]);  // 1

        Main.VALUES[0] = 1293812;

        System.out.println(Main.VALUES[0]);  // 1293812

    }
}
private static final Thing[] PRIVATE_VALUES = { ... };
public static final List<Thing> VALUES = 
  Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
private static final Thing[] PRIVATE_VALUES = { ... };
public static final Thing[] values() {
  return PRIVATE_VALUES.clone();
}

JAVA 9의 모듈 시스템

요약

참고 자료