Kotlin에서 싱글톤 만들기

David Mbochi Njonge 2023년6월20일
  1. Kotlin API를 사용하여 싱글톤 만들기
  2. 컴패니언 객체를 사용하여 싱글톤 만들기
  3. 컴패니언 객체를 사용하여 스레드로부터 안전한 싱글톤 만들기
  4. Lazy Initializer를 사용하여 싱글톤 생성
  5. 결론
Kotlin에서 싱글톤 만들기

디자인 패턴은 당면한 요구 사항을 기반으로 발생하는 일반적인 문제에 대한 솔루션 세트이며 이러한 솔루션은 동일한 문제를 해결하려는 다른 시스템에서 재사용할 수 있습니다. 생성, 동작 및 구조적 디자인 패턴을 포함하여 다양한 디자인 패턴이 있습니다.

생성 디자인 패턴은 객체가 생성되는 방식을 다루며, 이 튜토리얼에서는 생성 디자인 패턴의 예인 싱글톤 패턴을 사용하는 방법을 학습합니다.

싱글톤 패턴은 개체의 단일 복사본을 만들고 이에 대한 단일 액세스 지점을 제공하는 데 도움이 되는 디자인 패턴입니다.

응용 프로그램을 개발할 때 스레드 풀, 로깅, 장치 드라이버, 레지스트리 설정, 캐시 등에 대한 개체와 같은 개체의 단일 복사본이 필요한 경우가 있습니다.

이러한 개체의 여러 복사본이 있는 프로그램은 잘못된 동작, 리소스 남용 및 일관성 없는 결과를 초래할 수 있습니다. 이 튜토리얼에서는 Kotlin에서 싱글톤을 만드는 데 사용할 수 있는 다양한 방법을 배웁니다.

Kotlin API를 사용하여 싱글톤 만들기

Kotlin은 객체 생성 코드를 작성하지 않고도 즉시 사용할 수 있는 싱글톤을 제공합니다. 이를 달성하려면 object 키워드를 사용하여 싱글톤 이름을 정의해야 하며 이 싱글톤 내부에 멤버 변수와 함수를 추가할 수 있습니다.

IntelliJ를 열고 파일 > 새로 만들기 > 프로젝트를 선택합니다. 열리는 창에서 프로젝트 이름을 kotlin-singleton으로 입력하고 언어 섹션에서 Kotlin을 선택하고 빌드 시스템 섹션에서 Intellij를 선택합니다.

마지막으로 만들기 버튼을 눌러 프로젝트를 생성합니다.

src/main/kotlin 폴더 아래 Main.kt라는 파일을 만들고 다음 코드를 복사하여 파일에 붙여넣습니다.

object Singleton{
    fun showMessage(): Singleton {
        return Singleton
    }
}

fun main(){
    println(Singleton.showMessage())
    println(Singleton.showMessage())
}

위에서 언급했듯이 이것은 Kotlin에서 싱글톤을 생성하는 기본 방법이며 구현하기가 매우 쉽습니다. 생성된 싱글톤 객체는 스레드로부터 안전합니다. 즉, 다중 스레드 프로그램도 데이터 불일치로 이어질 수 있는 새 객체를 생성할 수 없습니다.

이 코드에서는 Singleton이라는 이름의 싱글톤과 showMessage()라는 멤버 함수를 만들었습니다. 이 함수는 생성된 싱글톤에 대한 참조를 반환합니다.

이 코드를 실행하고 멤버 함수에 대한 두 번의 호출이 아래와 같이 동일한 개체에 대한 참조를 반환한다는 점에 유의하십시오.

Singleton@5305068a
Singleton@5305068a

컴패니언 객체를 사용하여 싱글톤 만들기

이전 예제를 주석 처리하고 주석 뒤에 다음 코드를 복사하여 Main.kt 파일에 붙여넣습니다.

class Singleton private constructor(){
    companion object{
        var singleton = Singleton();
        fun getInstance(): Singleton{
            if (singleton == null){
                singleton = Singleton();
            }
            return singleton;
        }
    }
}


fun main(){
    println(Singleton.getInstance());
    println(Singleton.getInstance());
}

이전 예제와 이 예제의 유일한 차이점은 companion object가 클래스 내부에서 사용된다는 것입니다. Kotlin의 모든 정적 변수와 함수는 companion object 안에 배치됩니다.

이 코드에서 객체의 복사본 하나만 생성되도록 하는 getInstance()라는 메서드를 만들었습니다. 이를 준수하기 위해 constructor()를 비공개로 만들고 객체를 생성하기 전에 객체가 존재하는지 확인합니다.

이 접근 방식은 잘 작동하지만 스레드 안전하지는 않습니다. 응용 프로그램이 다중 스레드인 경우 getInstance() 메서드에 동시에 액세스할 수 있으므로 이전에 언급한 문제를 일으킬 수 있는 여러 개체가 생성됩니다.

다음 섹션에서는 싱글톤 스레드를 안전하게 만드는 방법을 보여줍니다.

이 코드를 실행하고 출력이 아래 표시된 동일한 개체에 대한 참조를 반환하는지 확인합니다.

Singleton@1f32e575
Singleton@1f32e575

컴패니언 객체를 사용하여 스레드로부터 안전한 싱글톤 만들기

이전 코드를 주석 처리하고 주석 뒤에 다음 코드를 복사하여 Main.kt 파일에 붙여넣습니다.

class Singleton private constructor(){
    companion object{

        private var singleton = Singleton();

        @Synchronized
        fun getInstance(): Singleton{
            if (singleton == null){
                singleton = Singleton();
            }
            return singleton
        }
    }
}

이 코드는 이전 코드와 유사합니다. 유일한 차이점은 getInstance() 메서드에 @Synchronized 주석을 추가했다는 점입니다.

이 접근 방식을 Java에서는 동기화된 메서드라고 합니다. 스레드 안전성은 잠금을 통해 구현됩니다.

개체에는 일반적으로 잠금이 있으며 스레드가 동기화된 메서드에 도달하면 개체 생성이 완료될 때까지 독점적으로 이 잠금을 획득하므로 다른 스레드가 이 메서드에 액세스할 수 없습니다.

다른 스레드가 잠금에 액세스하면 이미 개체가 있고 스레드는 새 스레드를 만들지 않고 기존 스레드를 사용합니다. 전체 방법 대신 코드의 한 부분을 동기화하는 데 도움이 되는 동기화된 블록을 사용하는 것과 같이 동기화를 달성하는 다른 방법이 있습니다.

동기화는 문제를 해결하지만 응용 프로그램의 성능 문제를 야기합니다. 동기화로 인해 응용 프로그램의 성능이 100만큼 감소하므로 응용 프로그램이 성능에 중요한 경우 이를 사용하는 것을 재고해야 합니다.

접근 방식을 사용하여 지연 초기화에서 즉시 초기화, 이중 확인 잠금으로 전환하거나 성능이 애플리케이션에 영향을 미치지 않는 경우 그대로 둘 수 있습니다.

Lazy Initializer를 사용하여 싱글톤 생성

이전 코드를 주석 처리하고 주석 뒤에 다음 코드를 복사하여 Main.kt 파일에 붙여넣습니다.

class Singleton{
    companion object{
        val singleton: Singleton by lazy {
            Singleton();
        }
    }

    fun showMessage(): Singleton {
        return Singleton.singleton
    }
}

fun main(){
    println(Singleton.singleton.showMessage())
    println(Singleton.singleton.showMessage())
}

이 코드에서 전달하는 인수를 사용하여 스레드로부터 안전한 Lazy 인스턴스를 생성하는 lazy() 함수를 사용하여 싱글톤을 생성했습니다. LazyThreadSafetyMode.SYNCHRONIZED를 사용하여 지연 인스턴스를 초기화하는 데 하나의 잠금만 사용되도록 합니다.

이 코드를 실행하고 출력이 아래 표시된 동일한 개체에 대한 참조를 반환하는지 확인합니다.

Singleton@3e3abc88
Singleton@3e3abc88

결론

이 튜토리얼에서는 Kotlin에서 싱글톤 객체를 생성하는 데 사용할 수 있는 다양한 방법을 배웠습니다. 다루는 접근 방식에는 object 키워드, companion objectlazy initializer 기능 사용이 포함됩니다.

동기화된 방법을 사용하여 컴패니언 개체를 사용할 때 싱글톤 개체가 스레드로부터 안전한지 확인하는 방법도 배웠습니다.

David Mbochi Njonge avatar David Mbochi Njonge avatar

David is a back end developer with a major in computer science. He loves to solve problems using technology, learning new things, and making new friends. David is currently a technical writer who enjoys making hard concepts easier for other developers to understand and his work has been published on multiple sites.

LinkedIn GitHub