일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- Queue
- 코딩테스트
- 코테
- 공개키 암호화
- Algorithm
- JPA
- data structure
- 알고리즘
- 자료구조
- 생성자
- dbms
- 암호학
- generic class
- dfs
- javascript
- 가상컴퓨팅
- 크루스칼
- cloud computing
- sql
- python
- 자바의정석
- spring
- JDBC
- Stack
- BFS
- MVC
- 클라우드 컴퓨팅
- Java
- jsp
- DB
- Today
- Total
PLOD
[Java] 싱글톤 패턴(Singleton pattern) 본문
singleton pattern
싱글톤 패턴은 하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴이다. 하나의 클래스를 기반으로 여러개의 개별적인 인스턴스를 만들 수 있지만 그렇게 하지 않고 하나의 클래스를 기반으로 단 하나의 인스턴스를 만들어 이를 기반으로 로직을 만드는 데 쓰이며 보통 데이터베이스 연결 모듈에 사용한다.
싱글톤 패턴의 장점은 하나의 인스턴스를 기반으로 해당 인스턴스를 다른 모듈들이 공유하여 사용하기 때문에 인스턴스를 생성 할 때 드는 비용이 줄어든다. 그렇기 때문에 인스턴스 생성에 많은 비용이 드는 I/O 바운드 작업에 많이 사용한다.
단점은 의존성이 높아지며 TDD(Test Driven Development)를 할 때 걸림돌이 된다. 싱글톤 패턴은 미리 생성된 하나의 인스턴스를 기반으로 구현하는 패턴이므로 각 테스트 마다 독립적인 인스턴스를 만들기가 어렵다.
dependency Injection
싱글톤 패턴은 사용하기가 쉽고 굉장히 실용적이지만 모듈간의 결합을 강하게 만들 수 있다는 단점이 있다. 이 때 의존성 주입(DI)을 통해 모듈 간의 결합을 조금 더 느슨하게 만들어 해결 할 수 있다.
앞의 그림처럼 메인 모듈이 직접 다른 하위 모듈에 대한 의존성을 주기보다는 중간에 의존성 주입자가 이 부분을 가로 채 메인 모듈이 간접적으로 의존성을 주입하는 방식이다. 이를 통해 메인 모듈은 하위 모듈에 대한 의존성이 떨어지게 된다. 참고로 이를 디커플링이 된다고 한다.
의존성 주입은 모듈들을 쉽게 교체할 수 있는 구조가 되어 테스팅하기 쉽고 마이그레이션 하기도 수월하다. 또한 구현 할 때 추상화 레이어를 넣고 이를 기반으로 구현체를 넣어주기 때문에 애플리케이션 의존성 방향이 일관되고, 애플리케이션을 쉽게 추론할 수 있으며, 모듈 간의 관계들이 조금 명확해진다.
하지만 모듈들이 더 분리되므로 클래스의 수가 늘어나 복잡성이 증가될 수 있으며 약간의 런타임 패널티가 생기기도 한다.
의존성 주입의 원칙은 다음과 같다.
1. 상위 모듈은 하위 모듈에서 어떠한 것도 가져오지 말아야 한다.
2. 둘 다 추상화에 의존해야 한다. 이 때, 추상화는 세부 사항에 의존하지 말아야 한다.
싱글톤 패턴 구현 방법
1. 단순한 메서드 호출
싱글톤 패턴 생성 여부를 확인하고 싱글톤이 없으면 새로 만들고 만들어진 인스턴스를 반환한다. 이 방법은 아래의 코드와 같이 여러 개의 쓰레드가 이 객체를 공유할 때 문제가 발생한다.
public class Singleton {
private static Singleton INSTANCE;
private Singleton(){};
public static Singleton getInstance() {
if (INSTANCE == null) {
return INSTANCE = new Singleton();
}
return INSTANCE;
}
2. synchronized
인스턴스를 반환하기 전까지 격리 공간에 놓기 위해 synchronized 키워드로 잠금을 할 수 있다. 최초로 접근한 스레드가 해당 메서드 호출시에 다른 스레드가 접근하지 못하도록 lock을 걸어 준다.
3. static 멤버
정적 멤버나 블록은 런타임이 아니라 최초에 JVM이 클래스 로딩 때 모든 클래스들을 로드할 때 미리 인스턴스를 생성하는데 이를 이용한 방법이다. 클래스 로딩과 동시에 싱글톤 인스턴스를 만든다. 그렇기 때문에 모듈들이 싱글톤 인스턴스를 요청할 때 그냥 만들어진 인스턴스를 반환하면 된다. 이는 편리한 방법 같지만 불필요한 자원 낭비라는 문제점이 있다. 싱글톤 인스턴스가 필요없는 경우도 무조건 싱글톤 클래스를 호출해 인스턴스를 만들어야 하기 때문이다.
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton(){};
public static Singleton getInstance() {
return INSTANCE;
}
4. Lazy holder
singleInstanceHolder라는 내부클래스를 하나 더 만듬으로써, Singleton클래스가 최초에 로딩되더라도 함께 초기화가 되지 않고 getInstance()가 호출될 때 singleInstanceHolder 클래스가 로딩되어 인스턴스를 생성하게 된다.
public class Singleton {
private Singleton(){};
public static Singleton getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
5. Double Checked Locking(DCL)
이중확인잠금(DCL)은 인스턴스 생성 여부를 싱글톤 패턴 잠금 전에 한번, 객체를 생성하기 전에 한번 2번 체크하면 인스턴스가 존재하지 않은 때만 잠금을 걸 수 있기 때문에 앞서 생겼던 문제점을 해결 할 수 있다.
6. enum
enum의 인스턴스는 기본적으로 thread safe한 점이 보장되기 때문에 이를 통해 생성 할 수 있다.
public enum EnumSingleton {
INSTANCE("hello");
private final String text;
EnumSingleton(String text){
this.text = text;
}
public void hello(){
System.out.println(" world");
}
}
'개발 공부 > Java' 카테고리의 다른 글
[Java] Java 기본 사용법 정리 (1) | 2024.07.20 |
---|---|
[Java] 제네릭 클래스(Generic Class) (0) | 2024.06.07 |
[Java] 연산자(Operator) (0) | 2023.09.12 |
[Java] 배열(array) (0) | 2023.09.04 |
[Java] 객체지향프로그래밍(Object-Oriented Programming, OOP) (0) | 2023.06.21 |