728x90
자바에서 클래스와 멤버의 접근 권한을 적절히 설정하는 것은 시스템의 유지 보수성과 확장성을 높이며, 보안성을 강화하는 데 중요한 역할을 한다. 이 원칙은 캡슐화(encapsulation)와 밀접하게 연관되어 있으며, 내부 구현을 숨기고 외부에 필요한 인터페이스만 공개하는 방식으로 시스템 설계를 한다.
캡슐화의 장점
- 시스템 개발 속도 향상: 내부 구현이 숨겨지므로, 외부에 영향을 주지 않고 자유롭게 수정 가능.
- 시스템 관리 비용 절감: 내부 구현의 변경이 외부에 미치는 영향을 최소화하여 관리가 용이해진다.
- 성능 최적화: 컴포넌트 간 상호작용이 제한되므로 성능 최적화가 가능하다.
- 재사용성 향상: 다른 시스템에서 재사용할 때, 내부 구현을 알 필요 없이 인터페이스만 사용하면 되므로 재사용성이 높아진다.
접근 제어 매커니즘을 통한 컴포넌트 설계
기본 원칙은 모든 클래스와 멤버의 접근성을 가능한 한 좁히는 것이다. 이를 통해 코드의 의도를 명확하게 하고, 불필요한 외부 접근을 차단한다. 접근 제어자는 클래스를 설계할 때 다음과 같은 규칙을 따라야 한다.
접근 제한자 설정
| 접근 제한자 | 같은 클래스 | 같은 패키지 | 상속 클래스(같은 패키지) | 상속 클래스(다른 패키지) | 다른 클래스(다른 패키지) |
|---|---|---|---|---|---|
| public | O | O | O | O | O |
| protected | O | O | O | O | |
| default (package-private) | O | O | O | ||
| private | O |
클래스 및 멤버 접근 제한
- Top-Level 클래스와 인터페이스는 외부에서 접근을 제어할 수 있도록
private또는default로 설정해야 한다. - 멤버 필드, 메서드는 그 접근 제한자를 상황에 맞게 설정해야 하며, 가능하면 외부에서 직접 접근할 수 없도록
private로 설정한다. - 상속을 고려할 때, 상위 클래스에서 선언된
package-private멤버는 하위 클래스에서protected나public으로 변경할 수 있지만, 더 좁은 범위인private으로 변경할 수 없다.
테스트를 위한 접근 제어 변경 금지
테스트 목적으로 클래스나 멤버의 접근 제한자를 변경하는 것은 피해야 한다. 테스트와 관련된 변경은 코드 품질을 저하시킬 수 있기 때문이다.
public 클래스와 인스턴스 필드
- public 클래스의 인스턴스 필드는 가급적
public으로 두지 말아야 한다.- 필드가 가변 객체를 참조하거나
final이 아닌 경우, 해당 필드는 불변성을 보장할 수 없다. public가변 필드를 갖는 클래스는 스레드에 취약할 수 있다.- 예외적으로 상수와 같은 구성 요소는
public static final로 공개할 수 있다. public class FixDiscountPolicy1000 implements DiscountPolicy { public static final int DISCOUNT_AMOUNT = 1000; ... }
- 필드가 가변 객체를 참조하거나
배열과 불변 리스트
- public static final 배열 필드는 가급적 사용하지 않아야 한다.
final키워드를 사용하더라도 배열의 내용을 수정할 수 있기 때문이다.- 대신, 배열을
unmodifiableList로 감싸 불변 리스트를 제공하거나, 배열의 복사본을 반환하도록 해야 한다. - 예시:*또는 배열을 복사하여 반환하는 방법:
private static final Integer[] VALUES = {5, 3, 2}; // 원본은 지킬 수 있다. public static final Integer[] values() { return VALUES.clone(); }private static final Integer[] VALUES = {5, 3, 2}; public static final List<Integer> VALUES_LIST = Collections.unmodifiableList(Arrays.asList(VALUES));
- 대신, 배열을
리스코프 치환 원칙(Liskov Substitution Principle)
리스코프 치환 원칙은 객체 지향 설계의 중요한 원칙 중 하나로, 상속 관계에서 하위 클래스가 상위 클래스를 대체할 수 있어야 한다는 규칙을 정의
상위 클래스의 객체가 하위 클래스 객체로 치환되어도 프로그램이 정상적으로 동작해야 한다는 것을 의미
잘못된 예시
class Parent {
// 부모 클래스에서 package-private (default) 접근 제한자로 선언
void doSomething() {
System.out.println("Parent doing something");
}
}
class Child extends Parent {
// 자식 클래스에서 부모 클래스의 doSomething 메서드를 private로 변경
@Override
private void doSomething() {
System.out.println("Child doing something");
}
}
올바른 예시
class Parent {
// 부모 클래스에서 package-private (default) 접근 제한자로 선언
void doSomething() {
System.out.println("Parent doing something");
}
}
class Child extends Parent {
// 자식 클래스에서 부모 클래스의 doSomething 메서드를 그대로 사용
@Override
void doSomething() {
System.out.println("Child doing something");
}
}
- 리스코프 치환 원칙에 의해, 상위 클래스에서
package-private로 선언된 멤버는 하위 클래스에서 더 넓은 접근 범위인protected또는public으로 변경할 수 있지만, 더 좁은 범위인private로 변경할 수 없다.
자바 9 이후 모듈 시스템
- 자바 9에서 도입된 모듈 시스템을 통해 외부에서의 접근을 제어할 수 있다.
module-info.java파일을 통해 공개할 클래스와 패키지를 지정하지 않으면, 해당 모듈 외부에서 접근할 수 없다. - 예를 들어, JDK에서 제공하는 일부 패키지는 모듈 내에서만 접근 가능하며 외부에서는 접근할 수 없다.
728x90
'Programming Language > Java' 카테고리의 다른 글
| [이펙티브 자바]Item.17-변경 가능성을 최소화하라 (0) | 2024.12.02 |
|---|---|
| [이펙티브 자바]Item.16-public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 (0) | 2024.12.02 |
| [이펙티브 자바]Item.14-Comparable을 구현할지 고려하라. (0) | 2024.11.25 |
| [이펙티브 자바]Item.13-clone 재정의는 주의해서 진행하라 (1) | 2024.11.20 |
| [이펙티브 자바]Item.12-toString을 항상 재정의하라 (0) | 2024.05.14 |