Design Pattern - Singleton

sam2·2022년 9월 20일
1

출처: https://refactoring.guru/design-patterns/singleton
매끄럽게 읽기 위한 의역이 포함될 수 있습니다.
틀린 부분이 있다면 의견주세요.

Intent

싱글톤(Singleton) 이란 클래스에 인스턴스가 하나만 있는지 확인하면서, 이 하나의 인스턴스에 접근하기 위한 전역 액세스 포인트(global access point)를 제공하는 창조적인 디자인 패턴

Problem 🙁

싱글톤 패턴은 단일 책임 원칙을 피해 아래의 두가지 문제를 해결하게 해준다:

  1. 클래스가 단 하나의 인스턴스만 사용하는지 확인한다. 어떤 사람이 이 많은 클래스의 인스턴스를 제어하기 위해 접근하려고 할까? 대부분의 이유는 공유된 리소스를 제어하기 위해 접근하려고 할 것이다─예를 들면, 데이터베이스나 파일같은 것들 말이다.

작동방식: 당신이 하나의 객체를 생성했는데, 조금 있따가 새로 하나 더 만들기로 했다. 새롭게 만든 객체를 사용하는 것 대신에, 기존에 이미 생성된 객체를 받게 된다.

단, 항상 디자인에 따라 생성된 새 객체를 반환해야 하므로 이 동작은 일반 생성자로 구현할 수 없다.

  1. 인스턴스로 접근할 수 있는 전역 액세스 포인트를 제공한다. 몇몇의 필수 객체를 저장하는데 사용한 전역 변수를 기억하는가? 매우 편리하지만 다른 코드가 잠재적으로 이 변수들을 덮어써서 앱을 충돌나게 할 수 있는 위험이 있다.

이 전역변수 처럼, 싱글톤 패턴은 프로그램 내 어디에서든 이 몇개의 객체에 접근할 수 있도록 해준다. 단, 다른 코드가 해당 인스턴스를 덮어쓰지 않도록 보호한다.

이건 또 다른 측면의 문제이기도 하다: 당신은 1번 문제를 해결하는 코드가 당신의 프로그램 전체에 걸쳐 흩어져있는 것을 원치 않는다. 특히 나머지 코드가 이미 종속되어 있는 경우 한 클래스 내에 있는 것이 훨씬 낫다.

요즘엔 싱글톤 패턴이 인기가 많아지면서 사람들은 위 문제중 하나만 해결하더라도 싱글톤이라고 부르기도 한다.

Solution 😎

모든 싱글톤 구현체는 보통 아래의 두가지 특징을 따른다:
1. 다른 객체가 new 연산자를 사용하지 못하도록 기본 생성자(contructor)를 private로 생성한다.
2. 생성자 역할을 하는 정적 생성 메서드를 만든다. 내부적으로 보면, 이 메서드는 private 생성자를 호출하여 개체를 만들고 정적 필드에 저장한다. 이 메서드에 대한 이후의 모든 호출은 캐시된 개체를 반환한다.

만일 당신의 코드가 싱글톤 클래스에 액세스 권한이 있다면, 싱글톤의 정적 메서드를 호출할 수 있게 된다. 그 메서드를 어디서 호출하든 항상 동일한 객체를 반환한다.

실제상황에 적용해보면 🏢

정부는 싱글톤패턴의 훌륭한 예시다. 하나의 국가에는 오로지 하나의 정부만을 가지고 있다. 정부를 구성하는 개개인의 신원과 관계없이 "○○의 정부"라는 이름은 책임자 그룹을 식별할 수 있는 글로벌 액세스 포인트가 된다.

의사코드 🧠

이 예제는 데이터베이스에 접속하는 역할을 하는 싱글톤 클래스다. 이 클래스는 public 생성자가 없기때문에, 이 객체를 접근하기 위해서는 getInstance 메서드를 호출해야만 한다. 이 메서드는 처음 생성된 객체를 캐시하고 모든 후속 호출을 반환한다.

/**
 * The Singleton class defines the `getInstance` method that lets clients access the unique singleton instance.
 */
class Singleton {
    private static instance: Singleton;
    /**
     * The Singleton's constructor should always be private to prevent direct
     * construction calls with the `new` operator.
     */
    private constructor() { }

    /**
     * The static method that controls the access to the singleton instance.
     *
     * This implementation let you subclass the Singleton class while keeping
     * just one instance of each subclass around.
     */
    public static getInstance(): Singleton {
        if (!Singleton.instance) {
            Singleton.instance = new Singleton();
        }

        return Singleton.instance;
    }

    /**
     * Finally, any singleton should define some business logic, which can be
     * executed on its instance.
     */
    public someBusinessLogic() {
        // ...
    }
}

/**
 * The client code.
 */
function clientCode() {
    const s1 = Singleton.getInstance();
    const s2 = Singleton.getInstance();

    if (s1 === s2) {
        console.log('Singleton works, both variables contain the same instance.');
    } else {
        console.log('Singleton failed, variables contain different instances.');
    }
}

clientCode();
profile
고양이 두마리를 모시고 있는 프론트엔드 코더(?)

0개의 댓글