-
private 생성자 또는 enum 타입을 사용해서 싱글톤으로 만들 것JAVA/Effective java 2020. 12. 29. 19:35
- 싱글톤은 흔히 쓰는 용어이다.
- 하나의 패턴의 이름이고 App을 통틀어서 해당 클래스의 인스턴스가 하나만 사용하는 패턴을싱글톤이라고 한다.
간단하게 싱글톤 패턴을 요약해보면
- 자기 타입에 대한 인스턴스를 private static으로 만들어 놓는다.
- private 한 생성자를 만든다. 이제 이 타입의 인스턴스는 new를 통해 만들 수 없다.
- static 한 get메서드를 통해서 이 하나의 인스턴스를 가져다가 쓸 수 있다.
( multi-thread 등의 환경을 고려한다면 좀 더 복잡한 형태가 될 것 )
- 이처럼 오직 한 인스턴스만 만드는 클래스를 싱글톤이라 부른다.
- 보통 함수 같은 Stateless 객체 또는 본질적으로 유일한 시스템 컴포넌트를 그렇게 만든다.
- 싱글톤의 단점으로는 사용하는 클라이언트 코드를 테스트하는 게 어렵다는 것이다.
- 싱글톤이 인터페이스를 구현한게 아니라면 mock으로 교체하는게 어렵기 때문이다.
- 싱글톤으로 만드는 방법은 두 가지가 있는데,
- 두 방법 모두 생성자를 private 으로 만들고 publis static 멤버를 사용해서 유일한 인스턴스를 제공한다.
1. 첫번째 방법
- public static final 한 인스턴스를 만들기.
- 이 elevis 라는 인스턴스는 static 이니깐 클래스 로딩 시점에 단 한 번만 초기화되면서 만들어지게 된다.
- 이 처음 만들어진 인스턴스가 계속 재사용하게 되는 것이다.
- 리플렉션을 사용해서 private 생성자를 호출하는 방법을 제외하면 (그 방법을 막고자 생성자 안에서 카운팅 하거나 flag를 이용해서 예외를 던지게 할 수도 있지만) 생성자는 오직 최초 한 번만 호출되고 Elvis는 싱글톤이 된다.
장점
- 이런 API 사용이 static 팩토리 메소드를 사용하는 방법에 비해 더 명확하고 더 간단하다.
static 팩토리 메소드
- 해당 인스턴스를 public이 아닌 private으로 만든다.
- 그리고 public으로 싱글톤을 반환하는 팩토리 메서드를 만드는 것.
장점
- API를 변경하지 않고도 싱글톤으로 쓸지 안 쓸지 변경할 수 있다. 즉 getInstance()를 사용하면 클라이언트의 코드를 변경하지 않아도 된다는 것.
- 처음엔 싱글톤으로 쓰다가 나중엔 스레드당 새 인스턴스를 만든다는 등 클라이언트 코드를 고치지 않고도 변경할 수 있다.
- 필요하다면 Generic 싱글톤 팩토리(아이템 30)를 만들 수도 있다.
- static 팩토리 메서드를 Supplier <Elvis>에 대한 메서드 레퍼런스로 사용할 수도 있다.
직렬화 (Serialization)
- 위에서 살펴본 두 방법 모두, 직렬화에 사용한다면 역직렬화 할 때 같은 타입의 인스턴스가 여러 개 생길 수 있다고 한다.
- 역직렬화 할 때 자바가 내부적으로 호출하는 것이 readResolve()이다
- 이 readResolve()에서 싱글톤 인스턴스를 리턴하게 해 주면 동일한 인스턴스를 리턴하게 되니 안전하다는 것
- 모든 인스턴스 필드에 transient를 추가하여 직렬화 하지 않을 수 도 있다.
Enum
- 직렬화/역직렬화 할 때 코딩으로 문제를 해결할 필요도 없고, 리플렉션으로 호출되는 문제도 고민할 필요 없는 방법이 있다.
- 이 타입에 인스턴스는 여러개를 만들지 않는 이상 INSTANCE 하나인 것이 자명하다.
- 코드는 좀 익숙치 않아도 싱글톤을 구현하는 최선의 방법이라고 한다.
- 하지만 이 방법은 Enum 말고 다른 상위 클래스를 상속해야 한다면 사용할 수 없다.
- (하지만 인터페이스는 구현할 수 있다.)
참고 자료
'JAVA > Effective java' 카테고리의 다른 글
불필요한 객체를 만들지 말자 (0) 2021.01.01 리소스를 엮을 때는 의존성 주입을 선호하라 (0) 2020.12.31 private 생성자로 noninstantiability를 강제할 것 (0) 2020.12.30 생성자 매개변수가 많다면 빌더 사용을 고려해보자 (0) 2020.12.28 생성자 대신 static 팩토리 메소드 고려해보기 (0) 2020.02.27