Java/Spring
싱글톤(Singleton) 패턴의 개념 및 사용
mad038
2024. 6. 18. 20:23
싱글톤(Singleton) 패턴이란?
- Singleton 패턴은 소프트웨어 디자인 패턴 중 하나로, 특정 클래스의 인스턴스가 단 하나만 생성되도록 보장하는 패턴입니다.
- 이 패턴은 클래스 자체에서 인스턴스를 생성하고 관리하는 방식으로, 전역 상태를 관리하거나 공통 자원을 효율적으로 사용하고자 할 때 사용됩니다
싱글톤의 사용 이유
싱글톤 패턴을 사용함으로써 얻을 수 있는 이점 중 하나는 메모리 낭비를 방지할 수 있다.
- 인스턴스의 유일성 보장
- 클래스 내에 유일한 인스턴스를 저장할 정적 변수를 선언합니다.
- 인스턴스를 생성하는 메서드는 해당 정적 변수에 접근하여 이미 생성된 인스턴스가 있는지 확인하고, 없으면 새로 생성하여 저장합니다.
- 전역 접근점 제공
- 인스턴스에 접근할 수 있는 정적 메서드를 제공합니다. 이 메서드는 클래스의 인스턴스를 반환하며, 여러 곳에서 호출하더라도 항상 같은 인스턴스를 반환합니다.
- 생성자 접근 제한
- 클래스의 생성자를 private 또는 protected로 선언하여 외부에서 직접 인스턴스를 생성하지 못하도록 합니다.
- 메모리 낭비를 방지
- 사용자가 요청을 보내면 몇 번이고 동일 객체를 생성하고 지우는 것으로 자원의 낭비가 생기는 것을 한번 new로 객체를 생성하고 해당 객체를 이후에도 사용하도록 공유(static)하면 메모리 낭비 문제를 방지할 수 있습니다.
- 명확성 제공
- 코드에서 Singleton 패턴을 사용함으로써 해당 클래스가 유일한 인스턴스만을 가질 것임을 명확하게 알 수 있습니다.
Singleton 패턴의 예제
public class Singleton {
// 유일한 인스턴스를 저장할 정적 변수
private static Singleton uniqueInstance;
// private 생성자: 외부에서 인스턴스를 생성하지 못하도록 제한
private Singleton() {
}
// 인스턴스를 반환하는 정적 메서드
public static Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// 기타 메서드
public void someMethod() {
// 기능 구현
}
}
- static영역에 인스턴스(uniqueInstance) 객체를 생성하고 이후 해당 인스턴스가 필요할 때 public static으로 선언된 getInstance() 메서드를 통해 최초에 만들어진 인스턴스를 getInstance() 메서드가 호출될 때마다 항상 사용하도록 합니다.
- 여기서 기본 생성자를 private로 선언하여 외부에서 new 키워드로 새로운 객체 생성을 못하게 막는것이 중요합니다.
Singleton 패턴의 문제점 및 단점
- 단일 책임 원칙 위반 가능성
- Singleton 클래스는 인스턴스 관리 책임까지 가지게 되므로 단일 책임 원칙(Single Responsibility Principle)을 위반할 수 있습니다. 클래스가 여러 역할을 가지면 코드가 복잡해지고 유지보수가 어려워질 수 있습니다.
- 전역 상태 관리의 문제
- 전역 상태를 가지므로, 코드의 다른 부분에서 이 상태에 의존하거나 변경할 수 있습니다. 이는 코드의 결합도를 높이고, 의도치 않은 부작용(side effects)을 발생시킬 수 있습니다.
- 테스트의 어려움
- Singleton 패턴은 전역 인스턴스를 사용하므로, 단위 테스트에서 독립성을 유지하기 어렵습니다. Mock 객체나 다른 인스턴스로 대체하기 어렵기 때문에 테스트 환경을 구축하는 데 어려움이 있습니다.
- 멀티스레드 문제
- 멀티스레드 환경에서 동기화 처리가 적절하게 되지 않으면 Singleton 인스턴스가 여러 개 생성될 수 있는 문제가 발생할 수 있습니다. 이로 인해 데이터 불일치나 예기치 않은 동작이 발생할 수 있습니다.
- 초기화 시점 제어의 어려움
- 지연 초기화(Lazy Initialization)를 사용할 경우, 첫 번째 호출 시점에 초기화가 이루어지기 때문에 초기화 지연으로 인한 성능 저하가 발생할 수 있습니다. 반대로, 이른 초기화(Eager Initialization)를 사용하면 필요하지 않은 시점에 미리 인스턴스를 생성하게 되어 메모리 낭비가 발생할 수 있습니다.
- 의존성 주입과의 비호환성
- 의존성 주입(Dependency Injection)을 사용하는 설계에서는 Singleton 패턴이 적합하지 않을 수 있습니다. Singleton 패턴은 인스턴스 생성을 스스로 관리하기 때문에, 외부에서 의존성을 주입하거나 관리하기 어려워집니다.
- 상속의 제한
- Singleton 클래스는 상속을 지원하기 어려울 수 있습니다. 하위 클래스에서 Singleton 패턴을 유지하려면 추가적인 구현이 필요하며, 이는 코드의 복잡성을 증가시킵니다.
- 클라이언트 코드의 결합
- Singleton 패턴을 사용하는 클라이언트 코드가 Singleton 클래스에 강하게 결합될 수 있습니다. 이는 코드의 유연성을 감소시키고, Singleton 클래스의 변경이 클라이언트 코드에 큰 영향을 미치게 할 수 있습니다.
- Serialization 문제
- Java와 같은 언어에서 Singleton 객체를 직렬화(Serialization)할 때, 역직렬화(Deserialization) 과정에서 새로운 인스턴스가 생성되는 문제가 발생할 수 있습니다. 이를 방지하기 위해 readResolve 메서드를 구현해야 합니다.
참고 자료
싱글턴 패턴
/ 디자인 패턴들 / 생성 패턴 싱글턴 패턴 다음 이름으로도 불립니다: Singleton 의도 싱글턴은 클래스에 인스턴스가 하나만 있도록 하면서 이 인스턴스에 대한 전역 접근(액세스) 지점을 제공하
refactoring.guru