잘 설계된 컴포넌트와 어설프게 설계된 컴포넌트의 차이는 내부 구현 정보를 외부로 부터 얼마나 잘 숨겼느냐다
정보은닉, 혹은 캡슐화라고 하는 이 개념은 소프트웨어 설계의 근간이 되는 원리다.
기본원칙은 간단하다 모든 클래스와 멤버의 접근성을 가능한 좁혀야 한다.
자바의 접근제한자는 다음과 같다
- public : 모든 곳에서 접근 가능
- protected : 같은 패키지에서는 자유롭게 접근 가능 | 다른 패키지에 있는 경우에는 하위 클래스(상속 관계)에서만 접근 가능.
- package-private :같은 패키지 내에서만 접근 가능, 다른 패키지에서는 접근 불가능.
- private : 해당 클래스에서만 접근 가능
멤버 접근성을 좁히지 못하게 방해하는 제약 한가지 있다.
상위 클래스의 메서드를 재정의할 때는 그 접근 수준을 상위 클래스에서보다 좁게 설정할 수 없다.
이는 리스코프 치환의 법칙을 지키기 위해서 필요하다.
public 가변 필드는 스레드에 안전하지 못하다
아니 애초에 가변필드 자체가 스레드에 안전하지 못하다. final 키워드를 사용하여 생선자에 처음 값을 설정하고 그 이후에는 값을 변경할 수 없게 설계해야 한다.
따라서 가변 필드에 private 접근 제어자를 두어도 public 으로 setter 함수를 둔다면 해당 객체는 스레드에 안전하지 못하고 해당 필드를 사용하는 메서드는 적절한 동기화가 필요하다.
가장 실수를 많이 하는 부분은 클래스내에 참조하는 객체가 수정 가능한 때 조심해야한다.
예를 들어 길이가 0이 아닌 public static final 배열 필드를 두거나 이 필드를 반환하는 접근자 메서드를 제공해서는 안된다.
이런 필드나 접근자를 제공한다면 클라이언트에서 그 배열의 내용을 수정할 수 있게 된다.
// 보안 허점이 있는 코드
public static final Thing[] VALUES = {...};
// 해결 방법 1 배열을 private로 수정 후 public 불변 리스트 추가
private static final Thing[] PRIVATE_VALUES= {...};
public static final List<Thing> VALUES =
Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES))
// 해결 방법 2 배열을 private 수정 후 그 복사본을 반환하는 것
private static final Thing[] PRIVATE_VALUES = {...};
public static final Thing[] values() {
return PRIVATE_VALUES.clone();
}
실제 실무에서는 접근제어자를 private 로는 잘하는데 대부분이 롬복을 사용하여 @Data 애노테이션을 사용하여 나도 모르게 @Setter 기능을 사용하여 객체가 불변하지 않게 설계를 하는 경우가 많으니 주의할것.
또한 클래스내에 객체를 참조하는 경우 특히 자바의 Date의 경우 외부에 노출로 인해 Date 객체를 통해 해당 클래스의 불변식을 무너트리거나 오작동하게 할 수 있으니 항상 주의할 것
'it 서적 독후감 > 이팩티브 자바' 카테고리의 다른 글
| [ITEM 18] 상속보다는 컴포지션을 사용하라 (0) | 2025.03.14 |
|---|---|
| [ITEM 17] 변경 가능성을 최소화 하라 (0) | 2025.03.13 |
| [ITEM 16] public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 (0) | 2025.03.11 |