디자인 패턴은 소프트웨어에서 자주 발생하는 문제를 해결하기 위한 재사용 가능한 설계 구조를 의미. 개발자들이 복잡한 문제를 효과적으로 해결할 수 있도록 도와주는 검증된 방법론. 코드의 가독성, 유지보수성, 확장성을 높이는 데 기여.
디자인 패턴은 일반적으로 생성(Creational), 구조(Structural), 행위(Behavioral) 세 가지
싱글톤 패턴은 클래스의 인스턴스가 오직 하나만 생성되도록 보장하며, 그 인스턴스에 접근할 수 있는 전역적인 접근점을 제공하는 디자인 패턴
Eager Initialization(즉시 초기화)
public class Singleton {
private static final Singleton INSTANCE = new Singleton(); // 인스턴스를 미리 생성
private Singleton() {
// private 생성자로 외부에서 인스턴스 생성 차단
}
public static Singleton getInstance() {
return INSTANCE;
}
}
Lazy Initialization(지연 초기화)
public class Singleton {
private static Singleton instance; // 초기에는 null
private Singleton() {
// private 생성자로 외부에서 인스턴스 생성 차단
}
public static Singleton getInstance() {
if (instance == null) { // 필요할 때 생성
instance = new Singleton();
}
return instance;
}
}
Thread-Safe Singleton(스레드 안전)
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() { // 동기화 처리
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
Double-Checked Locking(이중 검증 잠금)
public class Singleton {
private static volatile Singleton instance; // volatile 키워드 사용
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
사용 사례
Logger 클래스를 만들고, 프로그램 여러 부분에서 로그를 기록하도록 구현.ExecutorService를 사용하여 멀티스레드 환경에서 싱글톤 객체에 접근하는 테스트를 작성해 보세요.volatile 키워드가 없으면 어떻게 동작하는지도 실험.Spring에서 기본 빈 스코프는 Singleton입니다. 아래 과정을 통해 이를 실습해볼 수 있습니다.
싱글톤 확인
Spring에서 두 개의 컨트롤러나 서비스 클래스에서 같은 빈을 주입받아 동일한 인스턴스인지 확인.
예:
@Service
public class MyService {
public void printHashCode() {
System.out.println(this.hashCode());
}
}
@RestController
public class MyController {
private final MyService myService;
public MyController(MyService myService) {
this.myService = myService;
}
@GetMapping("/test")
public void test() {
myService.printHashCode();
}
}
위 코드를 실행해 /test를 여러 번 호출하여 동일한 hashCode() 값이 출력되는지 확인.
Prototype 스코프 비교
@Scope("prototype")을 사용해 동일한 빈을 매번 다른 인스턴스로 생성하도록 설정.@PostConstruct와 @PreDestroy로 확인.Spring을 사용하지 않고, 간단한 싱글톤 레지스트리를 만들어 관리해 보세요.
예: 아래 코드와 같이 특정 타입의 객체를 싱글톤으로 관리하는 SingletonRegistry를 구현.
public class SingletonRegistry {
private static final Map<String, Object> registry = new HashMap<>();
public static Object getInstance(String key, Supplier<Object> creator) {
return registry.computeIfAbsent(key, k -> creator.get());
}
}
public class Main {
public static void main(String[] args) {
Object instance1 = SingletonRegistry.getInstance("Logger", Logger::new);
Object instance2 = SingletonRegistry.getInstance("Logger", Logger::new);
System.out.println(instance1 == instance2); // true 출력
}
}
ApplicationContext를 사용해 빈을 직접 가져오고, 싱글톤 스코프의 동작 원리를 실험.ConfigurableApplicationContext를 사용해 컨텍스트를 닫으면 싱글톤 빈이 어떻게 소멸되는지 확인.SessionManager 클래스를 싱글톤으로 구현.SessionManager를 공유하며 세션 정보에 접근.이런 실습을 통해 싱글톤 패턴을 단순한 개념이 아니라 실무에 활용할 수 있는 도구로 만들 수 있습니다!