JAVA/Java Design Patterns

싱글턴 패턴( Singleton Pattern ) 과 static - Java 디자인 패턴

100win10 2020. 4. 28. 20:58

 

싱글톤 패턴이란?

 

  • 싱글턴 패턴은 일부 사람들이 static은 전역 변수와 같아 보이고 객체 지향이 아니라는 주장에
  • 이러한 비판을 해결하고자 나왔다고 볼 수 있다.

 

 

  • 애플리케이션이 시작될 때, 어떤 클래스가 최초 한 번만 메모리를 할당(static)하고
  • 해당 메모리에 인스턴스를 만들어 사용하고 공유하는 제한하는 패턴

 

  • 즉, 싱글톤 패턴은 '하나'의 인스턴스만 생성하여 사용하고 공유하는 디자인 패턴이다.
  • 인스턴스가 필요할 때, 똑같은 인스턴스를 만들지 않고 기존의 인스턴스를 활용하는 것!

 

다음과 같은 조건을 충족하는 개체에 적합하다.

 

1. 프로그램 실행 중에 최대 하나만 있어야 할 때 

  

2. 이 객체에 전역적인 접근이 가능해야 할때

 

 

 

좋은 예시는 Logger 가 있겠다.

 

Logger는 싱글톤으로 만들어서  error나 debug나 info 등의 정보 등을 App에서 공유하게 된다.

 

 

 

 

 

또 하나의 예는 JDBC에서 볼 수 있는데  해당 Data source는 커넥션 풀을 유지한다.

  • 커넥션 풀로부터 해당 프로그램들에게 연결을 담당한다.  우리는 App안에서 DB 커넥션을 필요로 하는  여러 클래스들을
  • 가질 수 있지만 DataSource는 하나의 인스턴스 만을 유지한다. 따라서 Singleton 패턴의 한 예라고 볼 수 있다.

 

 

 

 

 

싱글톤 DateUtil 클래스의 UML

 

다음은 싱글톤 패턴으로 만든 DateUtil 클래스에 UML이다.

 

 

1. 생성자는 private 하게 만들어 주어 어떤 다른 클래스들이 DateUtil을 초기화할 수 없게끔 만들어주어야 한다.

 

2. 그 후에 자신의 타입인 정적 필드를 하나 선언하고 역시 private 접근 제한자를 붙여 외부에서 필드 값을 변경하지 못한다.

 

3. 대신 외부에서 호출할 수 있는 정적 메서드인 getInstance 메서드를 선언하고 자신의 인스턴스를 갖는 정적(static) 필드를 리턴해준다. 리턴 값이 null이라면 생성해준다.

 

 

즉 private 생성자이고 static 변수이므로 static 메서드를 통해서만 객체를 얻어오는 상황이 된다.

 

아직 객체가 없다면? 

  • 객체를 생성 후 static 변수에 저장한다.
  • static 변수에 저장된 객체를 반환한다.

 

이미 객체가 있다면?

  • static 변수에 저장되어 있는 객체를 반환한다.

 

4. 외부에서 이 객체를 사용하는 방법은 오직 getInstance를 호출하는 것뿐이다. 그리고 이 getInstance 메서드는 오직

하나의 정적 필드만을 반환하게 된다.

 

 

해당 UML을 통해 구현해본 DateUtil 클래스이다.

 

 

 

 

 

 

 

메인 함수 분석

 

  • instance는 static 변수고 클래스 로딩 시점에 null로 초기화돼있다.
  • instance0은 null인 instance의 객체를 만들어준다.
  • instance1은 null이 아니므로 해당 객체를 그대로 반환하고 둘은 같은 주소를 가지게 된다.
  • 결과는 true가 나오게 된다.

 

 

 

 

static과 싱글턴에 차이는 무엇일까?

 

싱글턴에 비해 static은 할 수 없는 일

 

1. 다형성을 사용할 수 없다.

 

2. 싱글턴에서 멀티턴 패턴(하나가 아닌 여러 개 반환 즉 객체 최대 n개 반환)으로 바꿀 수 없다.

 

3.  객체의 생성 시점을 제어할 수 없다.

  • Java의 static은 프로그램 실행 시에 초기화된다.
  • 싱글턴은 getInstance 호출할 때 객체를 만드므로 제어가 그나마 가능하다.

 

 

 

싱글턴의 변형

 

getInstance()에 매개변수가 들어가야 하는 상황이 있다면 createInstance(매개변수)와 getInstance()를

따로 만들어 주기도 한다.

 

  • 프로그램 실행 시 -> createInstance(매개변수) 호출
  • 인스턴스가 필요시 getInstance()를 호출