본문 바로가기

Java/Java SE, EE

[Java/Java SE, EE] 싱글톤(Singleton)

싱글톤(Singleton)

객체 지향 프로그래밍에서 클래스는 동일한 속성과 행동을 갖는 객체를 만들기 위한 설계입니다. 하지만 모든 클래스가 여러 객체를 생성하는 것은 아니며, 때로는 애플리케이션에서 하나의 객체만을 위한 클래스를 설계하기도 합니다. 데이터 컨테이너나 로직, 서비스를 핸들링하기 위한 매니저(Manager) 또는 팩토리(Factory)라고 이름 짓는 클래스가 이에 해당합니다.

이처럼 매니저 또는 팩토리와 같은 객체는 애플리케이션에서 하나만 생성되며, 다수의 하위 종속되는 객체 또는 다른 서비스에서 이 객체를 참조할 필요가 있습니다. 객체의 참조를 위해서는 해당 객체가 생성될 때 변수에 저장된 참조 주소를 전달해야합니다. 객체가 유일하고 명확함에도 불구하고, 매번 객체의 참조 주소을 알려주는 것은 구조적으로 어쩔 수 없는 불편한 작업에 해당합니다.

싱글톤(Singleton)은 명확한 단일 객체에 대한 참조를 자유롭게 행할 수 있도록하는 디자인 패턴의 일종입니다. 싱글톤이 디자인 패턴의 일종인 이유는, 싱글톤의 구현을 위해서 많은 프로그래밍 언어가 별도의 키워드를 제공하지는 않기 때문입니다.

public class SomeSingleton {
   private static SomeSingleton instance = new SomeSingleton();
   
   public static SomeSingleton getInstance() {
      return instance;
   }
}

가장 기본적인 구조의 싱글톤 클래스는 이처럼 구성됩니다. 자기 자신의 대한 참조를 정적 멤버 변수(static)로 생성하고, 정적 멤버 함수를 사용하여 어느 위치에서든 이 싱글톤 객체를 사용 할 수 있도록 리턴합니다.

만약 싱글톤 객체가 생성되면서 객체의 초기화 작업이 필요하다면, 아래와 같이 getInstance() 과정에서 진행 할 수 있습니다.

public class SomeSingleton {
   private static SomeSingleton instance = null;
   
   public static SomeSingleton getInstance() {
      if (null == instance) {
         newInstance();
      }
      
      return instance;
   }
   
   private static SomeSingleton newInstance() {
      instance = new SomeSingleton();
      
      // 싱글톤의 초기화
      
      return instance;
   }
}

또는 정적 블록을 사용하여 더 단순화 할 수도 있습니다.

public class SomeSingleton {
   private static SomeSingleton instance = null;
   
   static {
      instance = new SomeSingleton();
      
      // 싱글톤의 초기화
   }
   
   public static SomeSingleton getInstance() {
      return instance;
   }
}

싱글톤 접근

싱글톤에 접근하기 위해서는, 싱글톤이 구현하는 정적 멤버 함수에 우선 접근해야 합니다. 상기 예시에서는 getInstance() 메소드에 해당합니다. getInstance()를 먼저 호출하면, 리턴 값에 해당하는 싱글톤 객체를 리턴받아 싱글톤 객체가 구현하는 메소드를 이어서 호출 할 수 있습니다. 아래 예시에서는 someSingletonMethod()에 해당합니다(싱글톤 객체의 행위).

public class SomeSingletonAccess {
   public void someMethod() {
      SomeSingleton.getInstance().someSingletonMethod();
   }
}

싱글톤이 객체 참조에 대한 스코프를 자유롭게 지원하는 반면, 여전히 객체 지향 프로그래밍이 지켜야할 요소를 잊어서 안됩니다. 싱글톤 객체의 행위에 대해서는 싱글톤 객체의 메소드를 호출하는 방식으로 처리하고, 필드에 대한 접근이 필요한 경우 getter/setter로 데이터를 은닉할 필요가 있습니다(캡슐화).