Singleton 패턴은 클래스의 인스턴스가 단일하게 유지되도록 보장하는 디자인 패턴입니다. 이 패턴은 어떤 클래스의 인스턴스가 하나만 존재하고, 이를 전역적으로 접근할 수 있는 방법을 제공합니다.

Singleton 패턴의 개요

Singleton 패턴은 다음과 같은 특징을 가집니다:

  • 클래스의 인스턴스가 오직 하나만 존재합니다.
  • 전역적으로 접근 가능한 접근점을 제공하여 어디서든 동일한 인스턴스에 접근할 수 있습니다.

Singleton 패턴은 다양한 상황에서 유용하게 사용될 수 있으며, 자주 사용되는 패턴 중 하나입니다.

Singleton 패턴의 장점

Singleton 패턴은 다음과 같은 장점을 가집니다:

  • 하나의 인스턴스만 존재하므로, 자원의 낭비를 줄일 수 있습니다.
  • 전역적인 접근점을 통해 인스턴스에 접근할 수 있으므로, 간편한 사용이 가능합니다.

Singleton 패턴을 잘못 사용하는 경우

Singleton 패턴을 잘못 사용하면 다음과 같은 문제가 발생할 수 있습니다:

  • 멀티스레드 환경에서 동기화 문제가 발생할 수 있습니다. 동시에 여러 스레드가 인스턴스 생성을 요청할 경우, 여러 인스턴스가 생성될 수 있습니다.
  • 테스트 용이성이 저하될 수 있습니다. Singleton 인스턴스가 의존성으로 주입되지 않고 전역적으로 사용되기 때문에 테스트하기 어려울 수 있습니다.
  • 단일 책임 원칙(Single Responsibility Principle)에 위배될 수 있습니다. Singleton 클래스가 다른 기능을 포함하면서 인스턴스 유일성을 유지하기 위한 코드가 추가될 경우, 클래스의 책임이 너무 많아질 수 있습니다.

잘못된 Singleton 패턴은 다음과 같은 문제를 일으킬 수 있습니다. 여러 스레드가 동시에 인스턴스를 생성할 수 있어서 여러 인스턴스가 생성되거나, 인스턴스의 일관성을 보장할 수 없는 경우입니다. 아래는 이러한 문제가 발생하는 잘못된 Singleton 패턴의 예시 코드입니다.

public class BadSingleton {
    private static BadSingleton instance;

    private BadSingleton() {
        // 인스턴스 생성 로직
    }

    public static BadSingleton getInstance() {
        if (instance == null) {
            // 여러 스레드가 동시에 이 부분에 진입할 수 있음
            instance = new BadSingleton();
        }
        return instance;
    }

    // 기타 기능 및 데이터 멤버
}

위의 코드에서 getInstance() 메서드는 여러 스레드가 동시에 인스턴스를 생성할 수 있는 문제가 있습니다. 여러 스레드가 동시에 instance가 null인 것을 확인하고 인스턴스를 생성하게 되면, 서로 다른 인스턴스가 생성될 수 있습니다.

이러한 상황에서는 동기화(synchronization) 문제를 해결해야 합니다. 아래는 동기화를 추가하여 올바르게 동작하는 Singleton 패턴의 예시 코드입니다.

public class GoodSingleton {
    private static GoodSingleton instance;

    private GoodSingleton() {
        // 인스턴스 생성 로직
    }

    public static synchronized GoodSingleton getInstance() {
        if (instance == null) {
            instance = new GoodSingleton();
        }
        return instance;
    }

    // 기타 기능 및 데이터 멤버
}

위의 코드에서 getInstance() 메서드에 synchronized 키워드를 추가하여 동기화하였습니다. 이를 통해 여러 스레드가 동시에 getInstance() 메서드에 접근하는 것을 방지하고, 하나의 스레드만이 인스턴스를 생성할 수 있도록 보장합니다.

올바르게 동작하는 Singleton 패턴은 멀티스레드 환경에서 안전하게 사용할 수 있습니다. 하지만 Singleton 패턴을 사용할 때는 주의해야 하며, 필요한 경우에만 사용하는 것이 좋습니다.

Singleton 패턴과 함께 사용하면 좋은 패턴

Singleton 패턴과 함께 사용하면 좋은 패턴으로는 Abstract Factory 패턴이 있습니다. Abstract Factory 패턴을 사용하여 Singleton 패턴으로 생성된 인스턴스를 활용할 수 있습니다. Singleton 패턴을 적용하여 팩토리 클래스의 인스턴스가 단일하게 유지되면, 일관된 객체 생성을 보장할 수 있습니다.

아래는 Singleton 패턴과 Abstract Factory 패턴을 함께 사용하는 예제 코드입니다.

// Singleton 패턴을 적용한 팩토

리 클래스
public class SingletonFactory implements AbstractFactory {
    private static SingletonFactory instance;

    private SingletonFactory() {
        // 인스턴스 생성 로직
    }

    public static synchronized SingletonFactory getInstance() {
        if (instance == null) {
            instance = new SingletonFactory();
        }
        return instance;
    }

    public AbstractProductA createProductA() {
        return new ConcreteProductA();
    }

    public AbstractProductB createProductB() {
        return new ConcreteProductB();
    }
}

// Abstract Factory 패턴을 위한 인터페이스
public interface AbstractFactory {
    AbstractProductA createProductA();
    AbstractProductB createProductB();
}

// 구체적인 제품 클래스
public class ConcreteProductA implements AbstractProductA {
    // 제품 A의 구현
}

public class ConcreteProductB implements AbstractProductB {
    // 제품 B의 구현
}

위의 예제 코드에서 Singleton 패턴을 적용한 SingletonFactory 클래스는 AbstractFactory 인터페이스를 구현합니다. SingletonFactory 클래스의 인스턴스는 Singleton 패턴에 따라 단일하게 유지되며, createProductA 및 createProductB 메서드를 통해 객체를 생성합니다.

이렇게 함께 사용되는 경우, Singleton 패턴을 통해 Abstract Factory 패턴의 구체 팩토리 클래스의 인스턴스가 단일하게 유지되므로, 일관된 객체 생성이 가능해집니다.