[디자인 패턴] 싱글톤 패턴 (singleton pattern)
1.1.1 싱글톤 패턴
하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴
하나의 클래스를 기반으로 여러 개의 개별적인 인스턴스를 만들 수 있지만, 그렇게 하지 않고 하나의 클래스를 기반으로 단 하나의 인스턴스를 만들어 이를 기반으로 로직을 만드는 데 쓰이며, 보통 데이터베이스 연결 모듈에 많이 사용한다.
다시 말해 클래스를 통해 생성할 수 있는 객체가 한개만 되도록 만드는 것이 싱글톤 패턴이다.
하나의 인스턴스를 만들어 놓고 해당 인스턴스를 다른 모듈들이 공유하며 사용하기 때문에 인스턴스를 생성할 때 드는 비용이 줄어드는 장점이 있다. 하지만 의존성이 높아지는 단점이 있다.
오직 유일한 객체를 통해서만 어떤 리소스에 접근해야하는 제약이 있는 상황에서 유용하다. 클래스를 사용하는 입장에서 실수롤 여러 번 객체 생성을 시도하더라도 내부적으로 오직 하나의 객체만 생성되고 사용된다.
class Singleton {
private static Singleton one;
private Singleton() {
}
public static Singleton getInstance() {
if(one==null) {
one = new Singleton();
}
return one;
}
}
public class Sample {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
System.out.println(singleton1 == singleton2); // true 출력
}
}
one 값이 Null 인 경우에만 객체를 생성하도록 하여 one 객체가 딱 한 번만 만들어지게 되어있다.
싱글톤 패턴의 단점
싱글톤 패턴은 TDD 를 할 때 걸림돌이 된다. TDD를 할 때 단위 테스트를 주로 하는데, 단위 테스트는 서로 독립적이어야 하며 테스트를 어떤 순서로든 실행할 수 있어야 한다.
하지만 싱글톤 패턴은 미리 생성된 하나의 인스턴스를 기반으로 구현하는 패턴이므로 각 테스트마다 '독립적인' 인스턴스를 만들기가 어렵다. 또한, 모듈 간의 결합을 강하게 만들 수 있다는 단점이 있다. 이때 의존성 주입을 통해 모듈간의 결합을 조금 더 느슨하게 만들어 해결할 수 있다.
의존성(종속성) 주입의 정의 및 중요성

의존성 주입(DI)은 소프트웨어 엔지니어링에서 사용되는 기술로, 외부 소스로부터 종속성을 제공하여 애플리케이션의 구성 요소를 분리할 수 있다. DI를 통해 보다 모듈화되고 테스트 가능한 코드를 작성할 수 있는 이점을 얻을 수 있다.
테스트 목적으로 종속성을 쉽게 mocking할 수 있으며 테스트에서 싱글톤 객체의 동작에 대해 걱정할 필요가 없다.
의존성 주입의 장점
- 모듈들을 쉽게 교체할 수 있는 구조가 되어 테스팅하기 쉽고 마이그레이션하기도 수월하다.
- 구현할 때 추상화 레이어를 넣고 이를 기반으로 구현체를 넣어 주기 때문에 애플리케이션 의존성 방향이 일관되고, 애플리케이션을 쉽게 추론할 수 있으며, 모듈 간의 관계들이 조금 더 명확해진다.
- 낮은 결합도로 변경에 용이하고, 다른 객체와의 협력 관계에 더 집중하게 해준다.
의존성 주입의 단점
- 모듈들이 더욱더 분리되므로 클래스 수가 늘어나 복잡성이 증가된다.
- 약간의 런타임 패널티가 생기기도 한다.
의존성 주입 원칙
- 상위 모듈은 하위 모듈에서 어떠한 것도 가져오지 않아야 한다.
- 둘 다 추상화에 의존해야 하며, 이때 추상화는 세부 사항에 의존하지 말아야 한다.
모킹(Mocking) 이란?
단위 테스트를 작성할 때, 해당 코드가 의존하는 부분을 가짜(mock)로 대체하는 기법
특정 컴포넌트를 테스트할 때, 테스팅 범위가 아니지만 의존성이 있는 다른 모듈이 있을 수 있다.
이를 실제 모듈로 불러와서 테스트 한다면 다음과 같은 문제가 생길 수 있다.
- 아직 개발되지 않은 모듈에 의존한다면 테스팅/개발이 어려움
- 다른 모듈에 의해 테스트 결과가 바뀔 수 있어, 해당 컴포넌트에 대해서만 독립적인 테스트를 할 수 없음
- 특정 기능만 분리해서 테스트한다는 ‘단위’ 테스트의 의미에 적합하지 않음
- 테스트 실행 속도가 떨어지고, 이는 프로젝트 규모가 커져서 한번에 실행할 테스트 케이스가 많아지면 더 큰 이슈가 될 수 있음
- CI/CD 파이프라인의 일부로 테스트가 자동화되어 자주 실행되어야 한다면 더 큰 문제가 됨