상세 컨텐츠

본문 제목

[Design Pattern] 싱글톤 패턴(Singleton Pattern) -1

Development/Java

by thisisnew 2019. 10. 22. 02:50

본문

반응형

 

자바의 디자인 패턴에서 단골로 등장하는 '싱글톤 패턴'에 대해 알아보도록 하겠습니다.

 

이 패턴은 인스턴스가 오직 하나만 생성되고, 생성된 인스턴스를 어디서든 접근하여 이용할 수 있게 만드는 패턴입니다.

 

싱글톤 패턴을 이해하기 위해서는 먼저 일반적인 객체 생성에 대해 알아야 하는데요.

 

아래의 예시를 보도록 하죠.


ClassName abc = new ClassName(); 

이 한 줄의 코드에는 다음과 같은 의미가 담겨 있습니다.

  1. new를 통해 메모리에 할당한다. 즉, 객체를 생성한다.
  2. 생성되는 객체의 형태는 ClassName이라는 이름을 가진 클래스이다.
  3. 생성 시 ClassName()이라는 디폴트 생성자를 이용, ClassName을 초기화시킨다.
  4. 마지막으로 생성된 객체에는 abc라는 이름표를 붙여서, abc라고 부르도록 한다.

이런 객체의 생성은 우리 주변에서도 쉽게 찾아볼 수 있는데요.

 

식당의 예를 들어보도록 하겠습니다.

 

탕수육 찹쌀탕수육 = new 요리();

 

탕수육이 먹고 싶어서 '찹쌀탕수육'이라는 메뉴를 주문하면(new) 즉석에서 만들어져서(요리) 나오죠?

 

이런 것을 우리는 '주문'이라고 하고 음식이 만들어지는 것은 언제나 주문이 '선행'되어야만 합니다.

 

그런데 주문을 여러 번 하면 음식도 여러 번 만들어지게 되는데요.

 

이렇게 만들어진 요리들은 메뉴명, 맛, 양, 향기 등등 같은 요리처럼 보이지만 전부 독립적인 별개의 음식들입니다.

 

마찬가지로, 우리가 객체를 여러번 생성하면, 생성된 객체들은 다 별개의 인스턴스인 것입니다.


그럼 객체를 생성할 때 주문을 넣는 것이 아니라, 사전에 미리 만들어 놓고 여럿이 접근하여 이용하는 상황을 생각해보도록 하겠습니다.

 

이번에도 우리 주변에서 비슷한 상황을 찾아보죠.

 

공공재가 하나의 예가 될 수 있는데요.

 

공공재는 우리가 필요할 때 만드는 것이 아니라, 이미 만들어진 것에 우리가 접근하여 이용하죠?

 

또 외부에서 마음대로 새로 생성할 수도 없습니다. '국립공원'같은 것을 떠올려보시면 되겠네요.

 

싱글톤 패턴도 이와 유사합니다.

  1. 외부에서 생성할 수 없고
  2. 메모리 영역에 미리 할당합니다.(Static area).
  3. 고정된 영역에 할당하므로 딱 정해진 만큼의 메모리만 사용하고, 더는 낭비하지 않습니다.
  4. 게다가 Static area에 할당된 객체는 JVM이 종료되는 즉, 프로그램이 종료되기 전까지는 계속 사용할 수 있습니다.

 

정해진 양의 메모리만 소비하며, 동일한 객체를 다 같이 이용하는 것.

 

이것이 싱글톤 패턴이 가지는 목적이라고 할 수 있습니다.

 

이제부터 코드를 통해 알아보도록 하죠.

//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)의 문제입니다.

 

다음 포스팅에서는 이에 대해 말씀드리도록 하겠습니다.

 

반응형

관련글 더보기

댓글 영역