싱글톤 패턴이란?

싱글톤 패턴이란 인스턴스를 하나만 만들어 사용하기 위한 패턴이다.

이번 Blackjack 미션에서 카드 객체를 싱글톤으로 만들게 되었다. 그 이유는 프로그램 실행 시 사용할 카드 객체가 무한대로 생성되는 것을 방지하기 위해서이다. 또한 카드 객체는 프로그램 전역에서 사용되므로 한번 생성한 카드 객체를 프로그램 전역에서 공유하는 것이 메모리를 아끼는 방법이라고 생각했다.

추가적으로 다른 크루가 짠 코드를 보니 하나의 프로그램이 실행되는 동안은 Dealer 또한 하나의 객체만 생성되어야 하므로 Dealer를 싱글턴으로 만들 수 있을 것 같다.

싱글톤 패턴의 필요성

싱글톤 패턴으로 구현한 Deck 예시

public class Deck {

    private static final Deck deck;

    private static List<Card> cards;

    private Deck() {
        List<Card> createdCards = CardFactory.of();
        cards = createdCards;
    }

    public static Deck getInstance() {
	if (deck == null) {
	    return new Deck();
	}
        return deck;
    }

		/* 생략 */
}

싱글턴 패턴의 특징

싱글턴 패턴의 단점

  1. 동시성 문제 멀티 스레드 환경에서 객체를 생성하고자 할 때 동시성 문제가 발생할 수 있다. 객체가 생성되기 전, 스레드 A가 조건 분기문을 실행하는 도중 이미 조건 분기문을 통과한 스레드 B에서 객체를 생성해버릴 수 있다. 그렇다면 스레드 A는 스레드가 B가 객체를 생성한 이후 또 하나의 객체를 생성하게 될 수 있다.

이 문제를 해결하기 위해 Synchronized를 사용하거나 Holder initialization를 사용할 수 있다.

  1. 객체 지향의 특성을 살리기 어렵다 생성자 접근제한자를 private으로 막아주고 있다. 상속을 했을 때 부모의 필드 또는 메서드에 접근할 수 있어야 하기 때문에 부모의 생성자를 먼저 호출한 뒤 자식 생성자를 호출한다. 즉, 상속 받은 자식의 생성자를 호출할 경우 반드시 부모 생성자를 호출해야 한다. 따라서 생성자를 private으로 막아준다면 상속을 할 수 없게되고, 상속을 할 수 없다는 것은 다형성과 같이 객체 지향의 특성을 활용하지 못하는 것과 같다.
  2. 객체지향 설계 원칙의 ‘개방-폐쇄 원칙’을 위반하게 된다. 리팩토링 시 전체 프로그램에 영향을 미칠 수 있다. 단일 객체가 생성되면 프로그램의 전역에서 사용되기 때문에 싱글톤 패턴에 사용된 메서드 또는 객체가 변경된다면 이를 사용하고 있는 모든 서비스에 영향을 미칠 수 있다. 즉, 객체의 접근 제한을 전역으로 열어둠으로써 다른 클래스 인스턴스 간 결합도가 높아진다.