싱글턴 패턴

ynkim·2024년 11월 28일
0

싱글턴

클래스에 인스턴스가 하나만 있도록 하면서 인스턴스에 대한 액세스 지점을 제공하는 패턴

구조

  • 싱글턴 클래스: 자체 클래스의 같은 인스턴스를 반환하는 정적 메서드 getInstance를 선언한다. 이 때 싱클턴의 생성자는 클라이언트로부터 숨겨져 있고 getInstance가 싱글턴 객체를 가져오는 유일한 방법이어야 한다.

예시 코드

class Database {
    private static volatile Database instance;

    private Database() {
        System.out.println("Connecting to the database...");
    }

    public static Database getInstance() {
        if (instance == null) {
            synchronized (Database.class) {
                if (instance == null) {
                    instance = new Database();
                }
            }
        }
        return instance;
    }

    public void query(String sql) {
        System.out.println("Executing query: " + sql);
    }
}

public class Application {
    public static void main(String[] args) {
        Database foo = Database.getInstance();
        foo.query("SELECT * FROM users");

        Database bar = Database.getInstance();
        bar.query("SELECT * FROM products");

        System.out.println("foo == bar: " + (foo == bar));
    }
}

장단점

장점

  • 클래스가 하나의 인스턴스만 갖는다는 것을 확신할 수 있다.
  • 인스턴스에 대한 전역 접근 지점을 얻는다.
  • 싱글턴 객체는 처음 요청될 때만 초기화된다.

단점

  • 인스턴스가 하나만 존재해야하는 점, 전역 접근 지점을 제공하는 점 두 가지 문제를 한 번에 해결하기 때문에 단일 책임 원칙을 위반한다.
  • 잘못된 디자인을 가릴 수 있다.
class ConfigManager {
    private static ConfigManager instance;
    private Map<String, String> configData;

    private ConfigManager() {
        configData = new HashMap<>();
        configData.put("db_url", "jdbc:mysql://localhost:3306/mydb");
        configData.put("api_key", "12345-ABCDE");
    }

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

    public String getConfig(String key) {
        return configData.get(key);
    }
}

class DatabaseConnection {
    public void connect() {
        String dbUrl = ConfigManager.getInstance().getConfig("db_url");
        System.out.println("Connecting to: " + dbUrl);
    }
}

class ApiService {
    public void callApi() {
        String apiKey = ConfigManager.getInstance().getConfig("api_key");
        System.out.println("Calling API with key: " + apiKey);
    }
}

public class Main {
    public static void main(String[] args) {
        DatabaseConnection dbConnection = new DatabaseConnection();
        dbConnection.connect();

        ApiService apiService = new ApiService();
        apiService.callApi();
    }
}
  • 다중 스레드 환경에서 싱글턴 객체가 여러번 생성되지 않도록 처리해야 한다.
  • 클라이언트 코드 단위 테스트가 어려울 수 있다.

Spring Bean 과의 차이점

특징SingletonSpring Bean
관리 주체클래스 자체Spring 컨테이너
스코프항상 단일 인스턴스기본 Singleton, 다른 스코프 가능
의존성 주입지원하지 않음DI 지원 (유연하고 테스트 친화적)
스레드 안전성직접 구현 필요Spring이 관리 가능
테스트 용이성낮음높음
확장성 및 유연성낮음높음

0개의 댓글