Design Pattern, Singleton

2022. 1. 26. 23:53ETC/Design Patterns

 

Object Creational Pattern

Singleton Pattern

 

-----------------    INDEX     -----------------

 

Singleton Pattern ?

Structure

Sample Code: Java

Race Condition

관련 패턴

 

----------------------------------------------

 

 

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

- GoF Design Patterns

 

싱글턴 패턴은 클래스 당 인스턴스를 하나만 존재하게 하고, 전역적인 접근 지점을 제공합니다.

 

 

프린터를 통해 문서를 출력한다고 해봅시다.

서로 다른 문서를 출력할 때마다 새로운 프린터를 하나씩 구비해야 한다면.. 큰 비용낭비가 되겠죠?

하나의 객체만을 사용해서 여기저기서 사용하면 효율적일테니까요.

 

싱글턴 패턴은 바로 이런 점에서 유용합니다.

단 하나의 인스턴스를 생성하고 전역적으로 공유합니다.

 

 

싱글턴 패턴을 제작하기 위한 효과적인 방법은 싱글턴 패턴 생성의 책임을 싱글턴 패턴 스스로에게 주는 것입니다.

어떻게 관리하는지 아래 예시를 볼까요? 

 

 

Structure

https://refactoring.guru/design-patterns/singleton

 

Singleton

클라이언트가 고유한 인스턴스에 액세스할 수 있는 메서드를 정의합니다.
자체 객체를 생성하는 책임을 가질 수 있습니다.

 

 

- instance: Singleton

싱글톤 패턴은 내부적으로 하나의 객체만 보장하기 위해 자체 객체를 저장하는 참조체(reference)를 갖고 있어서, 참조체를 통해 자신의 객체가 생성되었는지 판단합니다.

 

 

+ getInstance: Singleton

위의 그림에서 instance라는 속성으로 자체 객체를 참고하며, getInstance를 통해 자체 객체를 반환합니다.

이 과정에서 자체 객체가 생성되어 있는지를 확인하죠.

만약 존재하지 않는다면 새로 생성하고, 존재한다면 더 이상 생성하지 않고 생성되어있는 객체를 반환합니다.

이 과정을 통해 단 하나의 인스턴스를 사용함을 보장할 수 있습니다.

 

 

- Singleton()

단 하나의 인스턴스를 보장하기 위해서는 짚고 가야할 부분이 있습니다.

바로, new 를 막아야 합니다.

 

생성자를 private으로 설정하게 되면 새로운 인스턴스 생성을 막을 수 있습니다.

싱글턴 패턴에서 이 부분을 놓친다면 실수를 발생시킬 수 있습니다.

 

 

 

 

그렇다면 어떻게 이 싱글턴 객체를 외부에서 접근하게 만들까요?

바로 static을 사용합니다.

 

 

Static

Static 키워드는 변수와 메서드에 적용할 수 있습니다.

Static 키워드를 통해 선언된 멤버는 선언만으로 메모리에 할당되어 상주하게 됩니다.

메모리 할당을 딱 한번만 하게 되어 메모리 사용에 이점이 있습니다.

 

또, Static 키워드를 통해 정적 멤버들을 생성하면 Heap영역이 아닌 Static 영역에 할당됩니다.

같은 곳의 메모리 주소만을 바라보게 되어서 전역적으로 Static 변수의 값을 공유할 수 있는 것입니다.

즉, Static 영역에 할당된 메모리는 어디서든지 참조할 수 있다는 특징이 있죠.

 

이러한 Static 의 특징으로 싱글턴을 생성합니다. 

코드를 확인해보면 Singleton 패턴을 완전히 이해할 수 있을테니 확인해볼까요?

 

 

Sample Code: Java

Singleton

public class Printer {
    private static Printer printer = null;

    private Printer() { }

    public static Printer getPrinter(){
        if (printer == null) {
            printer = new Printer();
        }
        return printer;
    }
}

 

Client

public class Client {
    public static void main(String[] args) {
        Printer printer1 = Printer.getInstance();
        Printer printer2 = Printer.getInstance();
        System.out.println(printer1 == printer2);
    }
}

 

 

결과는 true가 출력됩니다.

 

 

 

Race Condition

= 경합조건

싱글턴 패턴을 사용할 때의 핵심은 인스턴스를 하나만 생성해야한다는 점인데요.

멀티스레드 환경에서는 이 조건을 위반할 가능성이 있습니다.

 

예를 들어, thread-1thread-2 스레드가 존재한다고 가정해봅시다.

thread-1getInstance의 if문 내로 들어가 생성하기 직전에, thread-2 가 if문을 통과할 수 있습니다.

두 개의 싱글턴이 생성될 수 있다는 문제점이 받아들여지시나요?

 

해결 방법은 두 가지로 간단합니다.

 

첫 번째는 인스턴스를 static으로 미리 만들어 둡니다.

 

public class Printer {
    private static Printer printer = new Printer();

    private Printer() { }

    public static Printer getInstance(){
        return printer;
    }
}

 

단, Printer를 사용하지 않을 때도 생성된다는 점을 주의하세요.

 

 

두 번째로는 getInstance를 동기 처리합니다.

 

package singleton;

public class Printer {
    private static Printer printer = null;

    private Printer() { }

    public synchronized static Printer getInstance(){
        if (printer == null) {
            printer = new Printer();
        }
        return printer;
    }
}

 

 

 

 

관련 패턴

C- Creational Patterns  |  S - Structural Patterns  |  B - Behavioral Patterns

 

 

C: Abstract Factory

추상 팩토리 채턴은 객체를 생성하는 패턴입니다. 이 패턴을 사용할 때, 구체화된 하나의 객체만을 생성할 수 있는데, 이때 싱글턴 패턴을 같이 적용해 족합적인 생성패턴을 설계할 수 있습니다.

 

 

C: Builder

빌더 패턴은 의존성있는 객체를 싱글턴으로 생성할 때 사용합니다.

관계에 따라 의존되는 객체의 생성 순서가 있을 수 있으며,

빌더는 생성 순서와 단계, 복합적인 절차 등을 다룹니다.

 

 

S: Facade

퍼사드 패턴은 외부에서 객체에 접근할 수 있는 단일 창구와 같은 개념입니다.

외부와 통신하는 객체를 하나만 만들면 효율적일 대, 단일화된 접속 지점으로 설계할 수 있습니다.

 

 

 

 

그럼 지금까지 Singleton Pattern에 대해 알아보았습니다.

오타나 잘못된 내용이 있다면 댓글로 남겨주세요!

감사합니다 ☺️ 

 

 

 

모든 Design Patterns 모아보기

 

Design Patterns

안녕하세요. GoF 디자인 패턴을 정리하고자 합니다. 디자인 패턴은 일주일 전부터 공부를 시작했는데, 스스로 설명하듯 적는게 익히는데 도움이 클 것같아 정말 오랜만에 시리즈로 포스팅하려

gngsn.tistory.com

 

 

 

'ETC > Design Patterns' 카테고리의 다른 글

Design Pattern, Decorator  (0) 2022.02.03
Design Pattern, Composite  (0) 2022.02.01
Design Pattern, Mediator  (0) 2022.01.24
Design Pattern, Adapter  (0) 2022.01.23
Design Pattern, Observer  (0) 2022.01.21