티스토리 뷰

반응형

1. 싱글톤 (Singleton) 이란?

 Ensure a class has only one instance and provide a global point of access to it.


- 해당 클래스의 인스턴스가 하나만 생성이 되는것을 보장하고, 어디서든지 그 인스턴스에 접근이 가능하도록 만드는 패턴

- 어플리케이션이 시작될 때, 어떤 클래스가 최초 한번만 메모리를 할당하고(Static) 그 메모리에 인스턴스를 만듬 

  = 그 이후에 생성자 시도한다면, 최초에 생성된 객체를 리턴하도록 함 (getInstance())

  = 객체가 다른 방법으로 생성되지 않도록 생성자를 Private로 구현한다.




2. 사용되는 곳


- 추상 팩토리, 빌더, 프로토타입 패턴을 구현할 때에 싱글톤을 사용할 수 있음

- 퍼사드 객체(Facade), 상태 객체(State) 는 종종 싱글톤으로 사용

- DBCP : DataBase Connection Pool), Thread Pool, 캐시, 로그 기록 객체 등






3. 구조 (UML 다이어그램)



(1) singleton private 멤버변수 선언 

(2) 생성자를 private로 선언하여 외부에 노출이 되지 않도록 함

(3) 이후에 Static으로 전역에서 접근이 가능한 메소드(getInstance)를 생성해서 인스턴스를 반환

     : 멤버변수에 이미 변수가 생성이 되어 있다면 해당 인스턴스를 리턴하며, 

 만약 인스턴스가 한번도 초기화 되지 않았다면, 생성한 후 리턴





4. 싱글톤 패턴을 사용하는 이유 - 장점


- 메모리 낭비 방지 : 한번만 new 로 인스턴스를 생성하기 때문

: 객체를 생성하게 되면 그 클래스의 인스턴스는 Heap 메모리에 올라가게 되고, 그 인스턴스를 가리키고 있는 변수는 Stack 메모리 영역에 생기게 된다. 이러한 작업 자체가 시간이 걸리는 일이며 한 객체를 여러번 new하게 되면 시간이 더욱 오래 걸리게 된다.

그래서 자주 사용되는 객체는 한번만 생성한 후, Heap에 존재하는 이 객체를 가리키도록만 만든다. 

=> 즉, 객체가 생성될 때 Heap 영역에 올라가는 시간과 메모리를 줄일 수 있다.

- 전역 인스턴스 이므로, 다른 클래스의 인스턴스에서 데이터 공유 용이

- 공통된 객체를 여러개 생성하여 사용하는 상황에서 유용 : ex) DB Pool

- 그 인스턴스를 오직 '한개'만 존재하는 것을 보증할 때 사용

- 두번째 호출 시 부터는 객체 로딩시간이 줄어서 성능이 좋아짐

- 불필요한 변수들로 전역 네임스페이스를 오염시키지 않음

- 상속이 가능하여 간단하게 사용 가능

- 실행시간에 초기화 됨 

: 게으른 초기화를 사용하는 것은 정적 변수와 차이가 있다 : 정적멤버변수는 정적 초기화 및 컴파일러가 변수의 초기화 순서를 보장하지 않으므로, 정적 변수끼리의 의존 불가능




5. 싱글톤 패턴의 유의점


- 멀티 스레드 기반의 어플리케이션에서 주의해야 함

객체가 아직 생성되지 않은 시점에서 동시에 생성자 호출 -> 동시에 객체 유무 체크 -> ※ 단 하나의 객체만 생성하도록 해야한다

뮤텍스, 세마포어의 기능을 지원할 경우, 싱글톤 객체 생성자의 "원자성"을 보장해야한다 

클래스에 상호배제(mutual exclusion)을 사용하여, 객체가 생성되고 있음을 알려야 한다 

-> 생성자에서 세마포어 등을 이용해서, 두개 이상의 스레드가 동시 접근이 불가능하도록 막을 필요가 있음






6. 싱글톤 단점


- 싱글톤을 사용하여 여러곳에서 효과적으로 호출할 수 있어서 편하지만, 결과적으로 프로그램의 Coupling을 높이게 되어 한곳에서의 변경이 다른 부분에 영향을 미치게 될 확률이 높아지게 된다.

 => 설계에 제약이 생긴다

- 초기화 시점(위치)을 제어할 수 없다 

 => 멀티 쓰레드 응용 프로그램에서 명시적 초기화가 필요한 경우, 쓰레딩 문제를 예방하기 위해서 조치가 필요





7. 예제 소스



using System;

  

namespace DoFactory.GangOfFour.Singleton.Structural

{

   

  class MainApp

  {

  

    static void Main()

    {

       

      Singleton s1 = Singleton.Instance();

      Singleton s2 = Singleton.Instance();

  

      if (s1 == s2)

      {

        Console.WriteLine("Objects are the same instance");

      }

  

      // Wait for user

      Console.ReadKey();

    }

  }

  

   //싱글톤 클래스

   class Singleton

  {

    private static Singleton _instance;

  

    //  'protected' 로 생성자를 만듦

    protected Singleton()

    {

    }

  

    // 'static'으로 메서드를 생성

    public static Singleton Instance()

    {

       

      //다중쓰레드에서는 정상적으로 동작안하는 코드입니다.

      //다중 쓰레드 경우에는 동기화가 필요합니다.

      if (_instance == null)

      {

        _instance = new Singleton();

      }

 

      //다중 쓰레드 환경일 경우 Lock 필요

      //if (_instance == null)

      //{

      //  lock(_instance)

      //  {

      //     _instance = new Singleton();

      //  }

      //}

  

      return _instance;

    }

  }

}

http://hongjinhyeon.tistory.com/29  



- 전역변수를 사용해서 싱글톤을 사용 안할 수도 있지만, 싱글톤은 전역변수를 사용하는데에서 발생하는 네임스페이스 충돌을 막을수가 있음

-싱글톤 패턴은 '게으르게' 인스턴스가 생성이 되므로, 객체가 자원을 많이 잡아 먹을때 유용한 생성기법 


  1. using UnityEngine;
  2. using System.Collections;
  3.    
  4. public class GameData
  5. {
  6.    
  7.     private static GameData instance=null;
  8.     public static GameData Instance
  9.     {
  10.         get
  11.         {
  12.             if (instance==null)
  13.             {
  14.                 instance = new GameData();
  15.             }
  16.             return instance;
  17.         }
  18.     }
  19.    
  20.     private GameData()
  21.     {
  22.     }
  23.    
  24.     public int _test; // 선언할 변수들
  25. }
  26.  
  27.  GameData.Instance._test;

                                                                          http://vaert.tistory.com/139


http://limkydev.tistory.com/67

https://jeong-pro.tistory.com/86?category=793347

반응형
댓글