이번 주제는 이전 ITEM 에서도 자주 거론됐던 private 생성자
이다. 객체의 수를 제한 두는 것이 왜 의미가 있는지는 ITEM 01 에서 설명했으니 한번 읽어보면 좋을 것 같다. 이번 글을 private 생성자
가 어떤 상황에서 필요한지를 중점으로 다룰 예정이다.
public class Something {
private Something(){}
}
다음과 같이 생성자 접근 제한자
를 private
로 설정하면 어떻게 될까?
더이상 해당 클래스의 객체
생성자는 접근 제한을 오로지 클래스 내부에 제한시켜 외부에서는 해당 생성자를 호출할 수 없다.
💡 접근 제한자란?
Java 에서 클래스, 필드, 생성자, 메소드를 접근할 수 있는 권한을 제한하는 키워드
- 참조하기 좋은 내용 : 접근제어자, 접근제한자
앞서 private 생성자
가 어떤 역할을 하는지 알았다.
그렇다면, private 생성자
를 이용하여객체
의 생성을 컨트롤하는 경우는 어떤게 있을까?
public class Singleton {
private static Singleton INSTANCE = new Singleton();
private Singleton(){}
}
싱글톤 (Singleton) 패턴
은 해당 클래스의 객체
의 수를 1개 로 제한을 두기 때문에 생성자를 이용한객체
생성을 막을 수 밖에 없다.
ITEM 03 에서 다뤘던 내용이니 한번 읽어보면 좋을 것 같다.
일부 클래스는 문자열 관련, 랜덤값 생성, 날짜 및 시간 처리 등 전역에서 사용되는 특정 로직이나 독립적인 기능을 구현해둔 클래스로 설계될 수 있다.
다음은 java에서 기본적으로 제공하는 java.util.Collections
코드의 일부이다.
public class Collections {
private Collections() {
}
private static final int BINARYSEARCH_THRESHOLD = 5000;
private static final int REVERSE_THRESHOLD = 18;
private static final int SHUFFLE_THRESHOLD = 5;
private static final int FILL_THRESHOLD = 25;
private static final int ROTATE_THRESHOLD = 100;
private static final int COPY_THRESHOLD = 10;
private static final int REPLACEALL_THRESHOLD = 11;
private static final int INDEXOFSUBLIST_THRESHOLD = 35;
@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
@SuppressWarnings({"unchecked", "rawtypes"})
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
...
}
java.util.Collections
클래스는 자바에서 컬렉션 프레임워크를 위한 유틸리티 메서드를 제공하는 유틸리티 클래스이다.
이 클래스는 모든 메서드 및 상수가 static
으로 선언되어 있기 때문에 객체
를 만들 필요가 없다.
public final class Constants {
// private 생성자로 외부에서의 인스턴스화 방지
private Constants() {
}
public static final int MAX_SIZE = 100;
public static final String DEFAULT_NAME = "John Doe";
}
상수 클래스란 주로 상수 값을 정의하고 관리하기 위한 클래스로,
메서드를 가지지 않고 모든 멤버가 상수이기에 위의 2번과 같이 static
으로 모두 선언되어 있어 객체
를 만들 필요가 없다.
public class Laptop {
private String brand;
private String model;
private int price;
private Laptop(){}
public static Laptop withBrand(String brand) {
Laptop laptop = new Laptop();
laptop.brand = brand;
return laptop;
}
public static Laptop withModel(String model) {
Laptop laptop = new Laptop();
laptop.model = model;
return laptop;
}
}
생성자를 통한 객체
생성을 막고 정적 팩토리 메서드
를 이용해서 객체
생성을 하는 방법이다.
해당 방법을 쓰는 이유에 대해서는 ITEM 01 에서 정리를 해둔 글이 있으니 한번 읽어보면 좋을 것 같다.
public class Car {
private final String brand; // 필수
private final String model; // 필수
private final String color; // 필수
private final String country; // 선택
private final int year; // 선택
private final int weight; // 선택
private Car (Builder builder) {
brand = builder.brand;
model = builder.model;
color = builder.color;
country = builder.country;
year = builder.year;
weight = builder.weight;
}
public static class Builder {
private final String brand; // 필수
private final String model; // 필수
private final String color; // 필수
// 선택 매개변수 기본값 초기화
private String country = ""; // 선택
private int year = 0; // 선택
private int weight = 0; // 선택
public Builder (String brand, String model, String color) {
this.brand = brand;
this.model = model;
this.color = color;
}
public Builder country(String country) {
this.country = country;
return this;
}
public Builder year(int year) {
this.year = year;
return this;
}
public Builder weight(int weight) {
this.weight = weight;
return this;
}
public Car build() {
return new Car(this);
}
}
}
빌더 (Builder) 패턴
은 매개변수가 많을 때 생성자를 통한 객체
생성이 아닌 내부 Builder
클래스를 따로 만들어 객체 생성 역할을 위임하는 방법이다.
해당 패턴을 쓰는 이유에 대해서는 ITEM 02 에서 자세하게 정리를 해뒀으니 한번 읽어보면 좋을 것 같다.
📑 정리
- private 생성자는 외부에서 생성자를 호출할 수 없다.
- private 생성자는 다양한 경우에 사용하지만, 주된 목적은 객체 생성을 컨트롤하기 위해서 필요하다.
🔎 참조