Book/면접을 위한 CS 전공지식 노트

[1장] 디자인 패턴과 프로그래밍 패러다임 - 싱글톤 패턴

muggle-coder 2023. 9. 17. 14:32
728x90

싱글톤 패턴(Singleton pattern)

하나의 인스턴스만 생성하고, 이 인스턴스를 전역적으로 접근 가능하게 만들어 사용하는 디자인 패턴

장점

  • 인스턴스가 오직 하나만 생성되기 때문에, 생성 비용이 줄어들어 메모리 사용량을 절약할 수 있다.
  • 전역적으로 접근 가능하기 때문에, 어디서든 쉽게 사용할 수 있다.
  • 하나의 인스턴스를 사용하기 때문에 인스턴스 간에 상태를 공유할 수 있다.
  • 여러 스레드가 동시에 인스턴스를 생성하려고 할 때, synchronized 키워드를 사용해 동시성 문제를 방지할 수 있다.

단점

  • 전역 상태를 유지하기 때문에 다른 객체 간의 의존성이 높아지고 코드 유지보수가 어려워질 수 있다.
  • 싱글톤 패턴은 테스트를 할 때 의존성 주입을 하지 않기 때문에 테스트 코드 작성이 어렵다.
  • 싱글톤 객체는 전역 상태를 유지하기 때문에 단위 테스트하기가 어렵다.

자바에서의 싱글톤 패턴

  • 자바에서는 중첩 클래스를 이용해 만드는 방법이 가장 대중적이다.
class Singleton {
		private static class singleInstatnceHolder {
				private static final Singleton INSTANCE = new Singleton();
		}
	
		public static Singleton getInstance() {
				return singleInstanceHolder.INSTANCE;
		}
}

public class HelloWorld {
		public static void main(String[] args) {
				Singleton a = Singleton.getInstance();
				Singleton b = Singleton.getInstance();
				System.out.println(a.hashCode());
				System.out.println(b.hashCode());
				if (a == b) {
						System.out.println(true);
				}
		}
}

-------
// 결과

1234
1234
true

의존성 주입

  • 싱글톤 패턴은 모듈 간의 결합을 강하게 만들 수 있다.
  • 이 문제를 의존성 주입(DI, Dependency Injection)을 통해 모듈 간의 결합을 조금 더 느슨하게 만들어 해결할 수 있다.
public class Singleton {
    private static Singleton instance;

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
  • 위 코드는 getInstance() 메서드를 호출해서 인스턴스를 가져올 수 있다.
  • 이 방식은 객체를 생성하는 코드가 한 곳에만 존재하기 때문에 객체 간의 결합도가 높아지게 되고 Singleton 클래스가 변경되면, 의존하고 있던 클래스에도 영향을 미치게 된다.
  • 의존성 주입을 사용하면 Singleton 객체를 생성하는 부분을 외부에서 주입받도록 변경할 수 있다.
  • 이렇게 하면 Singleton 클래스에 직접 의존하지 않고 중간에 의존성 주입자가 간접적으로 의존성을 주입해주기 때문에 객체 간의 결합도가 낮아지게 된다. 이를 ‘디커플링이 된다’라고 표현하기도 한다.
  • 객체 간의 결합도를 낮추면 객체를 변경하기 쉬워지기 때문에 유지보수성이 향상되고, 테스트 및 코드의 재사용성도 향상된다.

장점

  • 모듈들을 쉽게 교체할 수 있는 구조가 되어 테스트하기 쉽고 마이그레이션하기도 수월하다.
  • 구현할 때 추상화 레이어를 넣고 이를 기반으로 구현체를 넣어주기 때문에 애플리케이션 의존성 방향이 일관되고 모듈 간의 관계들이 명확해진다.

단점

  • 모듈들이 더욱 분리되므로 클래스 수가 늘어나기 때문에 복잡성이 증가될 수 있다.

의존성 주입 원칙

  • 상위 모듈은 하위 모듈에서 어떠한 것도 가져오지 않아야 한다.
  • 상위 모듈, 하위 모듈 모두 추상화에 의존해야 하며 추상화는 세부 사항에 의존하면 안된다.