singleton pattern은 인스턴스 생성패턴 중 하나로 인스턴스를 한 번만 생성하고 인스턴스의 내용을 여러 메소드에서 공유하여 사용할 수 있는 패턴이다.
싱글톤은 단 하나의 객체만을 생성하게 강제하는 패턴이다. 즉 클래스를 통해 생성할 수 있는 객체는 Only One, 즉, 한 개만 되도록 만드는 것이 싱글톤이다.
public class Configuration {
private static Configuration configuration;
private Configuration() {
}
public static Configuration getInstance() {
if (null == configuration) {
configuration = new Configuration();
}
return configuration;
}
}
sigleton pattern
은 생생자에 private키워드로 다른 클래스에서 Singleton 클래스의 생성자로의 접근을 막았다.이렇게 생성자를 private 으로 만들어 버리면 다른 클래스에서 Singleton 클래스를 new 를 이용하여 생성할 수 없게 된다. 동시에 인스턴스를 생성할 수 있는 특정 정적 메서드
를 통해서만 인스턴스를 생성하도록 하고 생성된 인스턴스는 정적 변수
에 저장하여 인스턴스에 접근할 수 있도록 합니다.
인스턴스를 생성하는 방법은 Configuration.getInstance()를 통해서만 생성할 수 있으며 configuration 정적 변수가 null
일 경우 생성자를 통해 인스턴스를 생성합니다.
Configuration configuration1 = Configuration.getInstance();
System.out.println(configuration1);
// 동일한 해시코드 Configuration@610455d6
Configuration configuration2 = Configuration.getInstance();
System.out.println(configuration2);
// 동일한 해시코드 Configuration@610455d6
최초 getInstance가 호출 되면 configuration이 null이므로 new에 의해서 객체가 생성이 된다. 이렇게 한번 생성이 되면 configuration은 static 변수이기 때문에 그 이후로는 null이 아니게 된다. 그런 후에 다시 getInstance 메소드가 호출되면 이제 configuration은 null이 아니므로 이미 만들어진 싱글톤 객체인 configuration을 항상 리턴한다.
여러번의 Configuration.getInstance() 호출에도 동일한 인스턴스의 참조 값을 반환하기 때문에 인스턴스를 생성함에 따른 메모리 공간을 절약할 수 있다.
※ 위에서 예제로 든 싱글톤은 Thread Safe 하지는 않다. 쓰레드 환경에서도 안전한 싱글톤을 만드는 방법은 따로 있다.
public class Configuration {
private static Configuration configuration;
private String cafeName = "카페";
private String cafeAddress = "저 먼나라 주소";
private Configuration() {
}
public static Configuration getInstance() {
if (null == configuration) {
configuration = new Configuration();
}
return configuration;
}
public String getCafeName() {
return cafeName;
}
public String getCafeAddress() {
return cafeAddress;
}
}
Configuration configuration1 = Configuration.getInstance();
System.out.println(configuration.getCafeName());
// 출력 "카페"
System.out.println(configuration.getCafeAddress());
// 출력 "저 먼나라 주소"
인스턴스 변수를 선언하여 사용하거나 메서드를 정의하여 일반적인 클래스처럼 사용할 수 있습니다.
인스턴스를 한번 생성하고 값을 공유한다면 굳이 Singleton Pattern의 인스턴스가 아니라 정적 변수와 정적 메서드로 만들어도 되지 않나요?
public class Configuration {
private static String cafeName = "카페";
private static String cafeAddress = "저 먼나라 주소";
public static String getCafeName() {
return cafeName;
}
public static String getCafeAddress() {
return cafeAddress;
}
}
System.out.println(Configuration.getCafeName());
// 출력 "카페"
System.out.println(Configuration.getCafeAddress());
// 출력 "저 먼나라 주소"
차이점은 인스턴스 지연 생성(Lazy Load)
이다.
정적 변수와 정적 메서드는 Method Area에 저장되며 프로그램 시작 시 메모리에 할당된다. 그 말은 해당 정적 변수나 정적 메서드를 프로그램에서 사용하지 않는다 하더라도 메모리 공간을 차지하게 됩니다.
그러나 Singleton Pattern
은 호출 하지 않는다면 최소 인스턴스의 참조 값을 저장하는 configuration 정적 변수와 인스턴스를 생성하기 위한 Configuration.getInstance() 정적메서드만 메모리에 할당됩니다.
진짜 필요할 때 Configuration.getInstance()를 호출하여 최초 메모리에 할당하는 지연 생성(Lazy Load) 이라는 차이점이 있다.
또한 configuration 정적 변수에 저장된 인스턴스의 참조 값을 null로 바꾸어 Heap메모리에 저장된 Configuration 인스턴스를 Garbage Collector가 수집할 수 있도록 할 수 있습니다.
public class Configuration {
private static Configuration configuration;
…
public void free() {
configuration = null;
}
…
}
Configuration configuration = Configuration.getInstance();
…
configuration.free();
singleton pattern 클래스로 좀 더 유동적으로 메모리를 사용할 수 있기 때문에 정적 변수와 정적 메서드와는 차이가 있습니다.