자바의 디자인 패턴에서 단골로 등장하는 '싱글톤 패턴'에 대해 알아보도록 하겠습니다.
이 패턴은 인스턴스가 오직 하나만 생성되고, 생성된 인스턴스를 어디서든 접근하여 이용할 수 있게 만드는 패턴입니다.
싱글톤 패턴을 이해하기 위해서는 먼저 일반적인 객체 생성에 대해 알아야 하는데요.
아래의 예시를 보도록 하죠.
ClassName abc = new ClassName();
이 한 줄의 코드에는 다음과 같은 의미가 담겨 있습니다.
이런 객체의 생성은 우리 주변에서도 쉽게 찾아볼 수 있는데요.
식당의 예를 들어보도록 하겠습니다.
탕수육 찹쌀탕수육 = new 요리();
탕수육이 먹고 싶어서 '찹쌀탕수육'이라는 메뉴를 주문하면(new) 즉석에서 만들어져서(요리) 나오죠?
이런 것을 우리는 '주문'이라고 하고 음식이 만들어지는 것은 언제나 주문이 '선행'되어야만 합니다.
그런데 주문을 여러 번 하면 음식도 여러 번 만들어지게 되는데요.
이렇게 만들어진 요리들은 메뉴명, 맛, 양, 향기 등등 같은 요리처럼 보이지만 전부 독립적인 별개의 음식들입니다.
마찬가지로, 우리가 객체를 여러번 생성하면, 생성된 객체들은 다 별개의 인스턴스인 것입니다.
그럼 객체를 생성할 때 주문을 넣는 것이 아니라, 사전에 미리 만들어 놓고 여럿이 접근하여 이용하는 상황을 생각해보도록 하겠습니다.
이번에도 우리 주변에서 비슷한 상황을 찾아보죠.
공공재가 하나의 예가 될 수 있는데요.
공공재는 우리가 필요할 때 만드는 것이 아니라, 이미 만들어진 것에 우리가 접근하여 이용하죠?
또 외부에서 마음대로 새로 생성할 수도 없습니다. '국립공원'같은 것을 떠올려보시면 되겠네요.
싱글톤 패턴도 이와 유사합니다.
정해진 양의 메모리만 소비하며, 동일한 객체를 다 같이 이용하는 것.
이것이 싱글톤 패턴이 가지는 목적이라고 할 수 있습니다.
이제부터 코드를 통해 알아보도록 하죠.
//Singleton.java
public class Singleton {
private Singleton() {}
private static Singleton single = null;
public static Singleton getInstance() {
if(single == null) {
System.out.println("싱글톤 생성...");
single = new Singleton();
}
return single;
}
}
Singleton 클래스를 위와 같이 작성합니다.
private Singleton() {}
코드를 살펴보면, 먼저 디폴트 생성자의 접근 제한자를 private으로 하였습니다.
이는 외부에서의 생성을 막겠다는 뜻이죠.
private static Singleton single = null;
public static Singleton getInstance() {
if(single == null) {
System.out.println("싱글톤 생성...");
single = new Singleton();
}
return single;
}
그리고 getInstance() 메서드에 static과 public을 붙여주었는데요.
미리 메모리에 올라간 메서드를 외부에서 이용할 수 있게 하기 위함입니다.
이 방식을 '게으른 초기화(Lazy Initialization)' 라고 부릅니다.
객체를 미리 생성하지 않고 null로 초기화해두었다가 필요할 때 생성하기 때문이죠.
//Instance.java
public class Instance {
public void getInstance() {
System.out.println("Instance 생성...");
}
}
이번에는 Singleton 클래스와 대조하여 확인할 일반적인 클래스를 하나 작성하도록 하겠습니다.
Main 클래스에서 저 두 개의 클래스를 불러와 대조해 보도록 하죠.
public class Main {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
Instance instance = new Instance();
instance.getInstance();
}
}
먼저 뚜렷한 특징이 한 가지 보이실 겁니다.
Singleton 클래스는 getInstance() 메서드에 바로 접근하는 반면, Instance 클래스는 객체를 생성 후 메서드에 접근한다는 것인데요.
Singleton 클래스는 객체 생성의 과정이 생략되었기 때문이죠.
이번에는 실행시켜서 결과를 보도록 하겠습니다.
정상적으로 실행되는군요.
하지만 아직 더 봐야 할 것이 있습니다.
정말로 싱글톤 객체는 동일한 객체를 사용하는지에 대한 여부 말이죠.
public class Main {
public static void main(String[] args) {
for(int i=0; i<3; i++) {
Singleton singleton = Singleton.getInstance();
System.out.println("singleton : " + singleton.toString());
}
for(int i=0; i<3; i++) {
Instance instance = new Instance();
instance.getInstance();
System.out.println("instance : " + instance.toString());
}
}
}
반복문을 이용하여 여러 번 생성해보도록 하겠습니다.
어떤가요? singleton은 동일한 객체를 바라보고 있죠?(노란색 박스)
심지어 '싱글톤 생성...'이라는 문구도 1번만 찍혔는데요.
처음에만 객체를 생성하고 그 후에는 생성된 것을 이용하기 때문입니다.
반면에, instance는 매번 새로운 객체를 생성하는 것을 알 수 있네요.(빨간색 박스)
자 이것으로 기본적인 싱글톤 패턴의 생성 원리와 사용법을 익혀봤습니다.
메모리의 낭비를 줄일 수 있고, 동일한 객체를 공유할 수 있는 이 패턴에도 실은 문제점이 있는데요.
바로 동기화(synchronized)의 문제입니다.
다음 포스팅에서는 이에 대해 말씀드리도록 하겠습니다.
리플렉션(Reflection) -2 (0) | 2019.10.28 |
---|---|
리플렉션(Reflection) -1 (0) | 2019.10.25 |
[Design Pattern] 싱글톤 패턴(Singleton Pattern) -2 (2) | 2019.10.22 |
[Design Pattern] 팩토리 메서드 패턴(Factory Method Pattern) (0) | 2019.10.21 |
문자열(String)의 빈 값 혹은 Null을 다루는 여러가지 방법 (0) | 2019.10.19 |
댓글 영역