[객체 생성 패턴] Chapter 1-1. Singleton Pattern : 가장 단순한 구현

 

✍️ Singleton, 인스턴스를 하나만 제공하는 클래스

싱글톤 패턴은 두 가지 목적이 있다.

1. 클래스의 인스턴스를 오직 하나만 제공한다.

2. 하나만 존재하는 인스턴스의 전역적인 접근점을 제공한다. 

 

예를 들어 어떤 소프트웨어의 환경설정은 오직 한 개만 존재해야 한다. 가령 게임의 환경설정이 여러 개일 때 혼란을 야기할 뿐이다. 

 

🍊 Singleton, 가장 단순한 구현

App 클래스에서 Settings 클래스의 인스턴스를 얼마든지 new를 통해 만들 수 있다. 

public class Settings {
}
public class App {
    public static void main(String[] args) {
        Settings settings1 = new Settings();
        Settings settings2 = new Settings();
    }
}

 

단, new를 통해 만들어진 인스턴스는 서로 같지 않다.

System.out.println(settings1 != settings2);

// true

 

싱글톤 패턴의 목적은 단 하나의 인스턴스를 제공하는 것으로, 외부에서 new를 사용해서 인스턴스를 만들게끔 허용하면 안 된다. 외부에서 new를 사용한 생성자를 쓰지 못하게끔 하려면 private 생성자를 만들면 된다.

public class Settings {
    private Settings(){}
}

 

private 생성자를 사용하게 되면 밖에서 인스턴스를 생성할 수 없기 때문에 Settings 클래스 안에서 인스턴스를 만들고 외부에서 접근할 수 있도록 전역적인 접근점을 제공해야 한다. 여기서 전역적인 접근점을 static 메서드로 구현할 수 있다.

public class Settings {
    private static Settings instance;

    private Settings() {
    }

    public static Settings getInstance() {
        if (instance == null) {
            instance = new Settings();
        }
        return instance;
    }
}
public class App {
    public static void main(String[] args) {
        Settings settings1 = Settings.getInstance();
        Settings settings2 = Settings.getInstance();

        System.out.println(settings1 == settings2);
    }
}

 

⚠️ 멀티 쓰레드에서 안전할까?

private 생성자와 static 메서드로 구현한 가장 심플한 싱글톤 패턴이다. 하지만 본 코드는 멀티쓰레드 환경에서 심각한 문제를 가지고 있다. 결론을 말하면 객체를 생성하는 부분을 여러 쓰레드가 동시에 접근할 때 쓰레드 별로 서로 다른 객체를 생성할 수 있고 이는 싱글톤 패턴의 목적에 어긋나게 된다.