2023. 11. 8. 23:39ㆍBook/이펙티브 자바
객체 생성과 파괴
- 배울 점
1. 객체를 만들어야 할 때와 만들지 말아야 할 때를 구분하는 법
2. 올바른 객체 생성 방법과 불필요한 생성을 피하는 방법
3. 제때 파괴됨을 보장하고 파괴 전에 수행해야 할 정리 작업을 관리
아이템1 : 생성자 대신 정적 팩터리 메서드를 고려하라
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE
}
클래스는 클라이언트에 public 생성자 대신 (Or 함꼐) 정적 팩토리 메서드를 제공할 수 있다.
- 장점 : 5
- 단점 : 2
장점 1. 이름을 가질 수 있다.
- 입력 매개변수의 순서 바꿔 시그니처가 같은 생성자를 만들 수 있지만 안좋은 발상!
=> 각 생성자의 역할을 구분하기 힘들다.
장점 2. 인스턴스 생성을 통제할 수 있다.
- 미리 만들어 놓거나 새로 생성한 인스턴스를 캐싱하여 재활용하는 식으로 불필요한 객체 생성을 피할 수 있다.
- 생성 비용이 큰 객체가 자주 요청되는 상황에 아주 좋다.(ex => new Int[1000000] 외 메모리,디스크 사용량,대역폭)
- 이유 : 인스턴스를 통제하면 싱글턴으로 만들 수도, 인스턴스화 불가로 만들 수도 있다. 또한 불변 값 클래스에서 동치인 인스턴스가 단 하나임을 보장할 수 있다. 플라이웨이트 패턴의 근간이 되며, 인스턴스가 하나만 만들어짐을 보장한다.
장점 3, 4, 5, 공통 예시
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
Enum<?>[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
장점 3. 반환 타입의 하위 객체를 반환할 수 있는 능력이 있다.
- API를 만들 때 이 유연성을 응용하면 구현 클래스를 공개하지 않고도 그 객체를 반환할 수 있어 API를 작게 유지할 수 있다. 이는 인터페이스 기반 프레임워크를 만드는 핵심 기술이기도 하다.
장점 4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.
- 반환 타입의 하위 타입이기만 하면 어떤 클래스의 객체를 반환하든 상관없다.
- 클라이언트는 객체가 어느 클래스의 인스턴스인지 알 필요도 없고 알 수도 없다. EnumSet의 하위 클래스이기만 하면 된다.
장점 5. 정적 팩토리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.
-
//StoreService 인터페이스를 구현한 MilkStoreService 라는 클래스가 없을 때
StoreService storeService = new MilkStoreService();
//=> MildStoreService 클래스가 없으므로 컴파일 에러 발생
//StoreService 인터페이스를 구현한 MilkStoreService 라는 클래스가 없을 때
StoreService storeService = StoreService.of("Milk");
//=> 컴파일 에러는 나지 않고 런타임 중 필요한 시점에 정적 팩토리 메서드 내에서 찾을 수 있으면 된다
- 이런 유연함은 *서비스 제공자 프레임워크(service provider framework)를 만드는 근간이 된다. (JDBC)
*이펙티브 자바에서는 서비스 제공자 프레임워크는 4개의 핵심 컴포넌트로 이뤄졌다고 한다.
- 서비스 인터페이스 : 구현체 동작 정의
- 제공자 등록 API : 구현체를 등록할 때 사용
- 서비스 접근 API : 클라이언트가 서비스의 인스턴스를 얻을 때 사용
- 서비스 제공자 인터페이스 : 서비스 인터페이스의 인스턴스를 생성하는 팩토리 객체를 설명
in JDBC
1.Connection => 서비스 인터페이스
2.DriverManager.registerDriver => 제공자 등록 API
3.DriverManager.getConnection => 서비스 접근 API
4.Driver => 서비스 제공자 인터페이스
단점 1. 생성자 메서드의 접근지시자가 private 일 경우 상속 x
단점 2. 정적 팩토리 메서드는 개발자가 찾기 어렵다.
- 자바doc 에서 생성자 메서드와 달리 일반 메서드는 찾기 어렵다.
- 그래서 메서드 이름을 지을 때 규약을 따라 짓는 식으로 문제를 완화해줘야 한다.
//of : 여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 집계 메서드
=> Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
//valueOf : from과 of의 더 자세한 버전
=> BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
//create 혹은 newInstance : instance 혹은 getInstance와 같지만,
//매번 새로운 인스턴스를 생성해 반환함을 보장한다.
=> Object newArray = Array.newInstance(classObject, arrayLen);
//getType : getInstance와 같으나, 생성할 클래스가 아닌
//다른 클래스에 팩터리 메서드를 정의할 때 쓴다 Type은 팩터리 메서드가 반환할 객체의 타입이다.
=> FileStore fs = Files.getFileStore(path);
//newType : newInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를
//정의할 때 쓴다. Type은 팩터리 메서드가 반환할 객체의 타입이다.
=> BufferedReader br = Files.newBufferedReader(path);
'Book > 이펙티브 자바' 카테고리의 다른 글
Item6 - 불필요한 객체 생성을 피하라 (0) | 2023.11.17 |
---|---|
Item5 - 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2023.11.16 |
Item4 - 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2023.11.15 |
Item3 - 생성자나 열거 타입으로 싱글톤임을 보증하라. (1) | 2023.11.14 |
Item2 - 생성자에 매개변수가 많다면 빌더를 고려하라 (0) | 2023.11.12 |