이펙티브 자바 책을 읽으며 내 생각을 바탕으로 정리하며 이해하기 위함이다.
생성자와 정적 팩터리 메서드
1. 생성자
클라이언트가 클래스의 인스턴스를 얻는 전통적인 수단은 public 생성자이고, 예시는 아래와 같다.
public class Car {
private final String type;
public Car(String type) { // ★ public 생성자
this.type = type;
}
@Override
public String toString() {
return "Car type: " + type;
}
public static void main(String[] args) {
Car car = new Car("Sports");
System.out.println(car); // Car type: Sports
}
}
2-1. 정적 팩터리 메서드
그런데 생성자와 별도로 정적 팩터리 메서드(static factory method) 를 제공할 수도 있는데, 다른 디자인 패턴들과 별개의 내용으로 이 책을 읽으며 처음 들어본 생소한 용어였다.
이는 그 클래스의 인스턴스를 반환하는 단순한 정적 메서드로, public 생성자 대신 (혹은 생성자와 함께) 제공할 수 있다.
설명으로는 잘 와닿지않아 코드를 통해 구현해보면 아래와 같다. 이를 통해 정적 팩터리 메서드를 활용하여 객체 생성 의도를 메서드 이름으로 명확하게 전달할 수 있음을 확인할 수 있었다.
public class Car {
private final String type;
private Car(String type) {
this.type = type;
}
public static Car createSportsCar() { // 정적 팩터리 메서드
return new Car("Sports");
}
public static Car createSedanCar() { // 정적 팩터리 메서드
return new Car("Sedan");
}
@Override
public String toString() {
return "Car type: " + type;
}
public static void main(String[] args) {
Car sportsCar = Car.createSportsCar();
Car sedanCar = Car.createSedanCar();
System.out.println(sportsCar); // Car type: Sports
System.out.println(sedanCar); // Car type: Sedan
}
}
2-2. 정적 팩터리 메서드의 장/단점
위 내용을 바탕으로 장점 5가지를 먼저 정리해보자.
- 이름을 가질 수 있다
: 정적 팩터리는 이름만 잘 지으면 반환될 객체의 특성을 쉽게 묘사할 수 있다.
/* 값이 소수인 BigInteger 반환하기 */
BigInteger bi1 = new BigInteger(2, 100, new Random()); // 생성자
BigInteger bi2 = BigInteger.probablePrime(2, new Random()); // 정적 팩터리 메서드 (특성묘사 O)
- 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다.
: 인스턴스 통제를 통해 싱글톤 / 인스턴스화 불가 로 만들 수 있다.
new BigInteger 와 BigInteger.probablePrime 을 비교해서 봐도 불필요한 객체 생성을 안하고있음을 알 수 있다.
- 반환 타입의 하위 타입 객체를 반환할 수 있다.
: 반환할 객체의 클래스를 자유롭게 선택할 수 있는 유연성을 가진다. 이로 인해 API의 유연성이 증가하고 구현 클래스를 공개하지 않고도 그 객체를 반환하여 api 를 작게 유지할 수 있다.
- 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.
: 반환 타입의 하위 타입이라면 어떤 클래스의 객체를 반환해도 상관없다. ( 예> EnumSet class )
- 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.
: 추상적인 인터페이스나 클래스일 수 있으며, 인터페이스나 클래스의 구체적인 구현이 없거나 미래에 추가될 수 있다.
이제 단점 2가지를 알아보자.
- 상속을 하려면 public 이나 protected 생성자가 필요하니 정적 팩터리 메서든 제공하면 하위 클래스를 만들 수 없다.
: 컬렉션 프레임워크의 유틸리티 구현 클래스들은 상속할 수 없다.
- 정적 팩터리 메서드는 프로그래머가 찾기 어렵다.
: API 설명에 명확히 드러나지 않기 때문에 사용자는 정적 팩터리 메서드 방식 클래스를 인스턴스화할 방법을 알아내야 한다.
정리
정적 팩터리 메서드와 public 생성자는 각자의 쓰임새가 있으니 상대적인 장단점을 이해하고 사용하는 것이 좋다.
그렇지만 정적 팩터리르 사용하는 게 유리한 경우가 더 많으므로 무작정 public 생성자를 제공하던 습관이 있다면 고치자.
정적 팩터리 메서드 용어를 새롭게 알게되어서 좋았다. 그렇지만 아직 이 장점과 단점에 대해 이해하기 위해서는 활용 사례를 좀 찾아봐야할 것 같다. 또한, 뒤에서 나오는 Item(주제) 들이 섞여있어서 끝까지 읽고 다시 한 번 위 글을 정리해봐야겠다.
참고
Bloch, J. (2018). Effective Java (3rd ed.).
'JAVA' 카테고리의 다른 글
[Java] LocalDateTime 과 Instant (0) | 2023.12.31 |
---|---|
[JAVA] 체크 예외와 언체크 예외 (2) | 2023.10.29 |
[Java] Access Level 에 관하여 (0) | 2023.09.24 |
[Java] stream.map() 동작 및 예제 (0) | 2023.08.20 |
[Java] record 사용방법 및 예제 (0) | 2023.08.06 |