출처: https://refactoring.guru/design-patterns/singleton
매끄럽게 읽기 위한 의역이 포함될 수 있습니다.
틀린 부분이 있다면 의견주세요.
싱글톤(Singleton
) 이란 클래스에 인스턴스가 하나만 있는지 확인하면서, 이 하나의 인스턴스에 접근하기 위한 전역 액세스 포인트(global access point)를 제공하는 창조적인 디자인 패턴
싱글톤 패턴은 단일 책임 원칙을 피해 아래의 두가지 문제를 해결하게 해준다:
작동방식: 당신이 하나의 객체를 생성했는데, 조금 있따가 새로 하나 더 만들기로 했다. 새롭게 만든 객체를 사용하는 것 대신에, 기존에 이미 생성된 객체를 받게 된다.
단, 항상 디자인에 따라 생성된 새 객체를 반환해야 하므로 이 동작은 일반 생성자로 구현할 수 없다.
이 전역변수 처럼, 싱글톤 패턴은 프로그램 내 어디에서든 이 몇개의 객체에 접근할 수 있도록 해준다. 단, 다른 코드가 해당 인스턴스를 덮어쓰지 않도록 보호한다.
이건 또 다른 측면의 문제이기도 하다: 당신은 1번 문제를 해결하는 코드가 당신의 프로그램 전체에 걸쳐 흩어져있는 것을 원치 않는다. 특히 나머지 코드가 이미 종속되어 있는 경우 한 클래스 내에 있는 것이 훨씬 낫다.
요즘엔 싱글톤 패턴이 인기가 많아지면서 사람들은 위 문제중 하나만 해결하더라도 싱글톤이라고 부르기도 한다.
모든 싱글톤 구현체는 보통 아래의 두가지 특징을 따른다:
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();