싱글톤을 만드는 방식은 여러가지가 있는데 그 중 정적 팩토리 메서드를 사용하여 만드는 방법을 살펴보자.
public class SingletonTest {
private static SingletonTest instance = new SingletonTest();
private SingletonTest() {
System.out.println("SingletonTest Instance Generated");
}
public SingletonTest getInstance() {
if (instance == null) {
instance = new SingletonTest();
}
return instance;
}
}
SingletonTest 클래스 생성자를 외부에서 호출할 수 없도록 생성자에 private을 사용했고 getInstance 메서드에는 객체가 초기화되지 않았을 때를 대비하여 인스턴스가 null값을 가질 때 새로운 인스턴스를 생성하도록 했다.
그런데, 정말로 외부에서 SingletonTest 인스턴스를 생성하지 못할까?
정답은 '생성할 수 있다' 이다.
자바의 리플렉션API를 사용한다면 private생성자를 호출할 수 있다.
Constructor<?> constructor = SingletonTest.class.getDeclaredConstructors()[0];
constructor.setAccessible(true);
SingletonTest singletonTest = (SingletonTest) constructor.newInstance();
AccessibleObject.setAccessible 메서드를 사용하면 private 생성자를 호출할 수 있다.
이를 막는 방법은 생성자를 다음과 같이 수정하여 두 번째 인스턴스가 생성되려 할 때 예외를 던지게 하면 된다.
public class SingletonTest {
private static SingletonTest instance = new SingletonTest();
private SingletonTest() {
// 두번째 인스턴스 생성시 예외 던지기
if (instance != null)
throw new AssertionError();
System.out.println("SingletonTest Instance Generated");
}
public SingletonTest getInstance() {
if (instance == null) {
instance = new SingletonTest();
}
return instance;
}
}
외부에서 생성자 호출 시 예외가 발생하는 것을 볼 수 있다.
'책 > 이펙티브 자바' 카테고리의 다른 글
이펙티브 자바 아이템29까지 읽고 느낀점 (1) | 2023.07.10 |
---|---|
자바 equals와 hashCode (0) | 2023.07.04 |
의존 객체 주입 패턴(Dependency Injection) (0) | 2023.07.02 |
생성자 대신 정적 팩토리 메서드를 고려하라 (0) | 2023.07.01 |