코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Singleton {
    // 클래스 내부에 유일한 인스턴스. 
    // 초기값을 두지 않고 getInstance 에서 생성하는 것을 lazy initialization 이라 하며, 메모리를 아낄 수 있으나 동시성 문제가 있을 수 있다.
    private static Singleton instance; // 여기서 new Singleton(); 를 두는 것을 early initialization 이라 하며, 메모리를 미리 할당하는 낭비가 있을 수 있으나 동시성 문제에서 비교적 자유롭다.

    // 생성자를 private으로 선언하여 외부에서의 인스턴스화를 방지
    private Singleton() {
        // 인스턴스 초기화 코드 ...
    }

    // 인스턴스에 접근할 수 있는 public 메서드
    public static Singleton getInstance() {
        // 인스턴스가 아직 생성되지 않았다면 생성
        if (instance == null) {
            instance = new Singleton();
        }

        // 유일한 인스턴스를 반환
        return instance;
    }

    // 예시로 추가한 메서드
    public void showMessage() {
        System.out.println("Hello, Singleton!");
    }
}

public class Main {
    public static void main(String[] args) {
        // Singleton 인스턴스 획득
        Singleton singleton = Singleton.getInstance();

        // Singleton 클래스의 메서드 호출
        singleton.showMessage();
    }
}
  • 주요 특징

    • 생성자private 으로 선언, 외부에서 인스턴스화를 방지한다.

    • getInstance 같은 메소드를 두어서 객체를 얻을 수 있게 한다.

    • 그 자신의 인스턴스static 속성으로 갖고 있는다.

  • 고려할 점

    • lazy initialization 에서 스레드 안정성

    • DIP를 고려한 싱글튼 클래스 사용

      • DIP란, ‘특정 클래스를 참조해서 사용해야 할 땐 그 클래스를 직접 참조하는 것이 아니라 그 대상의 상위 요소(추상 클래스 or 인터페이스)로 참조하라’는 원칙인데, 위 코드의 구현은 싱글튼 클래스의 메소드를 직접 호출하여 참조하고 있어, 구체적인 구현에 직접 의존하는 것이 되어 DIP 위반으로 볼 수 있다.

      • DI 패턴을 사용하여 인스턴스 관리 책임을 외부에 맡도록 하면 이러한 DIP 위반을 해소할 수 있다. 구체적으로 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public interface SingletonInterface {
    void showMessage();
}

public class Singleton implements SingletonInterface {
    //...
}

public class SomeService {
    private SingletonInterface singleton;

    public SomeService(SingletonInterface singleton) {
        this.singleton = singleton;
    }

    public void performAction() {
        singleton.showMessage();
    }
}

public class Main {
    public static void main(String[] args) {
        SingletonInterface singletonInstance = Singleton.getInstance();
        SomeService service = new SomeService(singletonInstance);
        service.performAction();
    }
}