조슈아 블로크 님의 "Effective Java" 책을 정리한 포스팅 입니다.
1. 상속 주의사항
재정의할 수 있는 메서드들이 내부적으로 어떻게 사용되는지 문서화하기
API 호출에 사용되는 경우
/**
* Removes all elements from this collection.
*
* Implementation Requirements:
* This method internally calls `removeRange(0, size())`.
* If `removeRange` is overridden in a subclass, the behavior of this method
* will change accordingly.
*/
public void clear() {
removeRange(0, size());
}
- Implementation Requirements 적어주기
- 호출 순서
- 호출 결과의 영향
- 예상치 못한 동작 변경이 없도록 설계해야 함
생성자는 재정의 가능한 메서드를 호출해서는 안됨
public class Super {
public Super() {
overrideMe(); // 재정의된 메서드 호출
}
public void overrideMe() {
System.out.println("super method");
}
}
public class Sub extends Super {
private String str; // 초기화되지 않은 상태
public Sub() {
str = "Sub String"; // 여기서 초기화됨
}
@Override
public void overrideMe() {
System.out.println(str); // str이 초기화되지 않았으므로 null 출력
}
public static void main(String[] args) {
Sub sub = new Sub();
}
}
- 상위 클래스의 생성자 내부에서 호출한 메서드가 하위 클래스에서 재정의된 경우, 하위 클래스의 메서드가 호출됨
- 하지만 이 시점에서 하위 클래스의 생성자가 아직 완료되지 않아 예기치 않은 동작이 발생할 수 있음
훅 메서드는 protected로 보호하기
protected void removeRange(int fromIndex, int toIndex) {
ListIterator<E> it = listIterator(fromIndex);
for (int i = 0, n = toIndex - fromIndex; i < n; i++) {
it.next();
it.remove();
}
}
- 상속받은 클래스가 원하는 동작을 추가하거나 변경할 수 있도록 공개된 메서드
- 하위 클래스에서 재정의하여 중간에 동작을 삽입할 수 있는 적절한 훅 메서드를 제공해야 함
- protected로 공개하여 하위 클래스가 재정의할 수 있도록 설계
2. 컴포지션 사용하기
상속은 캡슐화를 깨뜨림
- 상속은 하위 클래스가 상위 클래스의 구현 세부 사항에 의존하게 만듬
- 상위 클래스의 내부가 변경되면 하위 클래스의 동작에 이상이 생길 수 있음
컴포지션 사용
- 기존 클래스를 확장하는 대신, 다른 클래스의 인스턴스를 private 필드로 포함하여 기능을 확장
Wrapper Class
Decorator Pattern
'Java' 카테고리의 다른 글
[Effective Java] 4-4. 클래스와 인터페이스: 클래스 (0) | 2024.12.27 |
---|---|
[Effective Java] 4-3. 클래스와 인터페이스: 인터페이스 (0) | 2024.12.27 |
[Effective Java] 4-1. 클래스와 인터페이스: 클래스와 멤버의 접근 권한을 최소화하라 (0) | 2024.12.27 |
[Effective Java] 3. 모든 객체의 공통 메서드 (0) | 2024.12.27 |
[Effective Java] 2-8. 객체 생성과 파괴: 소멸자 사용을 피하라 (3) | 2024.12.27 |