싱글톤 패턴

이정석·2023년 5월 31일
0

디자인패턴

목록 보기
7/23

싱글톤 패턴이란?

인스턴스를 하나만 유지하고 싶을 때 사용하는 패턴으로, 전역변수를 사용하지 않고 객체를 전역적으로 액세스할 수 있는 방법을 제공할 수 있다.


문제상황

1. 다음과 같은 로그를 남기는 Logger클래스가 있다 하자.

public class Logger {
    public void log(String message) {
        System.out.println(message);
    }
}

2. 시스템 내의 여러군데에서 Logger클래스를 사용하려면 다음과 같이 사용해야 한다.

public class Client {
    public static void main(String[] args) {
        Logger logger1 = new Logger();
        Logger logger2 = new Logger();
        
        logger1.log("This is from logger1");
        logger2.log("This is from logger2");
    }
}

위 코드의 Logger 클래스는 파일에 저장하지 않고 print하는 코드이다. 만약 로그 메시지를 파일에 저장한다고 가정해보면, 각 Logger 인스턴스마다 파일에 쓰기 작업을 수행하게 되기 때문에 동일한 파일에 동시에 여러 번 쓰기를 시도하게 될 수 있다. 이런 경우에는 데이터가 꼬이거나 누락될 수 있다.

Logger를 사용할 때 같은 객체를 사용하도록 하자!


구조

  1. Singleton: 인스턴스를 하나만 유지하기 위해 사용하는 클래스로 다음과 같은 특징이 있다.
  • 실제 인스턴스 instance는 외부 접근을 막기 위해 private으로 한다.
  • 단 하나의 Singleton객체를 위해 생성자를 private으로 한다.
  • instance에 대한 접근은 getInstance로만 한다.
  • instancegetInstance는 static으로 선언한다.

    instance에 접근할 때 다른 코드는 Singleton.getInstance()로 instance를 받을 수 있다.


코드(JAVA)

1. Singeton

public class Singleton {
    private static Singleton instance;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

getInstance함수는 instance가 null일 때를 구분해 최초 실행 시 instance를 생성하도록 구현한다.


lazy initialization

getInstance함수를 보면 instance를 생성하기 전에 null인지 확인한다.

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

하나의 인스턴스를 제공하기 위해 기존에 생성되어있는지 확인하는 것은 당연하다!

인스턴스를 생성하기 전에 null인지 체크하고 객체를 생성하는 방법을 lazy initialization이라 한다. Singleton객체를 사용하지 않을 때는 생성 즉 메모리를 할당하지 않는다는 것이다.

lazy initialization을 사용하지 않으면 instance를 정의할 때 바로 생성해주어야 한다.

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

멀티 쓰레드 환경

멀티 쓰레드 환경에서 lazy initialization을 사용하면 복수의 객체가 생성될 수 있다. 바로 instance가 null일 때 동시에 2개 이상의 쓰레드로부터 getInstance가 호출될 때이다. 예를 들면, 쓰레드A와 B가 있다 할 때 쓰레드A가 instance=new Singleton()에 접근하기 직전에 쓰레드B가 if(instance==null)에 접근하는 것이다. 결국 new Singleton()이 두번 실행되는 상황이 된다.

Critical Section

위 문제 상황을 해결하기 위해 임계 구역(Critical Section)을 형성한다. JAVA에서는 synchronized를 사용하지만 C++에는 뮤텍스를 사용하는 방법이 있다.

profile
게임 개발자가 되고 싶은 한 소?년

0개의 댓글