싱글톤이란?
클래스의 인스턴스를 단일화해서 언제 어떤 때에 불리더라도
인스턴스를 새로 만드는 일 없이 같은 주소를 리턴해주는 디자인 방법을 이야기 한다.
이펙티브 자바3에서는 싱글톤 패턴의 종류에 대해서 적고 있다.
1. Public final 필드 이용
public class NutrtionFacts {
private String name = "name";
public static final NutrtionFacts INSTANCE = new NutrtionFacts();
private NutrtionFacts(){}
public void setName(String name)
{ this.name = name; }
public String getName()
{ return name; }
}
public class Main {
public static void main(String[] args) {
NutrtionFacts nutrtionFacts = NutrtionFacts.INSTANCE;
NutrtionFacts nutrtionFacts2 = NutrtionFacts.INSTANCE;
nutrtionFacts.setName("홍길동");
System.out.print(nutrtionFacts2.getName());
}
}
이전 포스트에서 테스트 했던 클래스를 재활용 했다.
nutrtionFacts를 바꿔도, nutrtionFacts2 도 바뀌는 모습을 확인할 수 있다.
생성자를 닫고 정적 변수 하나를 만들어줘서
어디서나 이용할 수 있게끔 만들어주는 것이다.
장점은 아주 간단해서 사용하기 쉽다. 하지만 사용하지 않을 때도 무조건 생성되서 메모리 낭비가 될 수 있고
또한, 변수 생성과 동시에 인스턴스가 생성되기 때문에 인스턴스에 초기값 설정 등이 불가능 하다
정적변수를 다룰 때는 신중해야된다는 점에서 볼 때 바람직하지 않은 방법이다.
2. static 이용하기
public class NutrtionFacts {
private String name = "name";
public static final NutrtionFacts INSTANCE;
static {
// 처리
INSTANCE = new NutrtionFacts();
// 처리
}
private NutrtionFacts(){}
public void setName(String name)
{ this.name = name; }
public String getName()
{ return name; }
}
위 코드 그대로에서 인스턴스의 생성 시점만 바꿨다.
이러면 초기값 설정 등은 할 수 있다. 하지만 무조건 생성된다는 점은 아직도 문제다
3. 정적 팩토리 이용하기
public class NutrtionFacts {
private String name = "name";
public static final NutrtionFacts INSTANCE = new NutrtionFacts();
private NutrtionFacts(){}
public static NutrtionFacts getInstance(){
return INSTANCE;
}
public void setName(String name)
{ this.name = name; }
public String getName()
{ return name; }
}
정적 모세도를 하나 만들어서 그 메소드를 통해 리턴하는 것이다.
형태만 바뀌었을 뿐 안쓸 때도 생성된다는 문제점은 여전하다.
4. IF문 처리
public class NutrtionFacts {
private String name = "name";
public static NutrtionFacts INSTANCE;
private NutrtionFacts(){}
public static NutrtionFacts getInstance(){
if(INSTANCE==null){
INSTANCE = new NutrtionFacts();
}
return INSTANCE;
}
public void setName(String name)
{ this.name = name; }
public String getName()
{ return name; }
}
내가 여지껏 써왔던 방법이다.
getInstance 메소드가 호출됐을 때 인스턴스를 생성한다.
하지만 단점이 존재한다. 나는 스레드를 다루어 본적이 많이 없어서 체감을 잘 못하지만
이 경우 스레드 충돌의 경우가 생길 수 있다. 그래서
public static synchronized NutrtionFacts getInstance(){
if(INSTANCE==null){
INSTANCE = new NutrtionFacts();
}
return INSTANCE;
}
이런 식으로 싱크처리를 해주면 되지만, 싱크처리는 순차적으로 처리를 하기 때문에 성능 저하는 피할 수 없다.
5. enum 클래스 이용
public enum NutrtionFacts {
INSTANCE;
private String name = "name";
public static NutrtionFacts getInstance(){
return INSTANCE;
}
public void setName(String name)
{ this.name = name; }
public String getName()
{ return name; }
}
이펙티브 자바에서는 이넘 클래스를 이용해서 사용하는 방법이 가장 좋은 방법이라고 한다.
먼저 이 클래스는 직렬화가 아무리 복잡하게 이루어질지라도 단일 인스턴스를 보장하고
멀티스레드를 사용할 때 충돌의 염려가 없다.
또한 이넘 밸류는 자바 어느 곳에서든 접근이 가능하고, 리플렉션 공격으로부터 안전하다는 점도 있다.
'프로그래밍 > Java' 카테고리의 다른 글
이펙티브 자바 규칙 4 - 객체 생성은 private 생성자로 막자 (0) | 2018.01.27 |
---|---|
이펙티브 자바 규칙 2 - Builder 패턴 (0) | 2018.01.24 |
이펙티브 자바 규칙 1 - 정적 팩토리 메소드 (0) | 2018.01.23 |