Singleton 패턴

DongHeon·2022년 10월 31일
0

디자인 패턴

목록 보기
1/12

Swift를 사용하다 보면 특정 객체들이 Singleton 패턴을 이용해 구현된 걸 확인할 수 있다.
예를 들어 UIApplication 같은 경우 공식 문서를 보면 iOS 앱은 하나의 UIApplication 인스턴스를 가지고 있다고 나와있다.

Singleton?

  • 단 하나의 인스턴스를 생성하는 패턴이다.
    여러 객체에서 하나의 인스턴스만 사용할 수 있다.
  • 하나의 인스턴스에 접근할 수 있는 방법을 제공한다.

문제점

  • Singleton 패턴 같은 경우 멀티 스레드 환경에서 안전하지 않다는 문제점이 존재한다. 즉, thread-unsafe 하다.

Thread safe란? 멀티 스레드 환경에서 어떤 함수나 객체가 여러 스레드에 의해 동시에 접근 되더라도 문제없이 각 스레드에서 원하는 결과가 도출 된다는 것을 의미한다.

여러 스레드에서 싱글톤 객체에 접근할 때 해당 객체가 유일한 객체인지 보장할 수 있는지에 대해 고민해 봐야 한다.
1. 미리 인스턴스화해서 사용한다.
2. 중첩 타입을 활용한다?

코드

Java

Java에서는 중첩 타입을 이용해 thread-safe 한 Singleton 객체를 만든다고 한다.

class DefaultSetting {
    private init() { }
    
    private class DefaultSettingHolder {
        static let shared = DefaultSetting()
    }
    
    static func shared() -> DefaultSettingHolder {
        return DefaultSettingHolder.shared
    }
}
// Java를 잘 몰라 Swift로 비슷하게 구현(참고만 하세요.)

타입(static) 변수를 통해 thread-safe 한 Singleton 객체를 구현할 수 있지만 Java같은 경우 타입 변수로 해당 Singleton 객체를 생성하면 해당 객체를 당장 사용하지 않더라도 메모리에 할당되기 때문에 메모리 낭비가 발생해 위 코드처럼 작성하는 방법이 존재하는 걸로 알고 있다.

Swift

Swift에서도 타입 프로퍼티를 이용해 Singleton 객체를 구현하는 데 그렇다면 여기서도 메모리 낭비가 발생하는 게 아닌가라는 고민을 할 수 있다.

Apple blog를 보면 해답을 찾을 수 있다.

The lazy initializer for a global variable (also for static members of structs and enums) is run the first time that global is accessed, and is launched as dispatch_once to make sure that the initialization is atomic.

전역 변수에 대한 초기화는 최초 접근할 때 초기화된다고 한다.

class DefaultSetting {
    static let shared = DefaultSetting()
    
    private init() { }
    
    func doSomething() {
    	....
    }
}

타입 프로퍼티를 활용해 전역에서 접근할 수 있는 객체를 생성해 하나의 인스턴스라는 것을 보장하고 private init을 통해 더이상 인스턴스를 생성하지 못하도록 코드를 작성해야 한다.

장단점

Singleton 패턴의 장점

  • 인스턴스를 하나만 생성하기 때문에 메모리 효율이 좋다.
  • 여러 객체에서 데이터 공유가 쉽다.

Singleton 패턴의 단점

  • 객체간의 결합도가 높아진다.
  • 수정과 테스트가 어렵다.
  • 멀티 스레드 환경에서 동기화 처리하지 않았을 때 인스턴스가 2개 생성될 수 있다.

해당 글은 인프런의 코딩으로 학습하는 GoF 디자인 패턴 강의와 예전 부트캠프를 통해 학습한 내용을 바탕으로 작성했습니다. 부족한 부분이나 잘못된 부분이 있다면 많이 알려주세요. 😭

0개의 댓글