코틀린 기반으로 쓰여짐
기사 시험을 공부하다보면 싱글톤 패턴이라는 것을 만나게 된다.
사실 처음 기사시험을 공부할때나 학과 공부를 할때 이게 그래서 왜 필요한데에 관한 의문을 정말 많이 가졌다.
안드로이드를 공부하다보니, 자원의 효율적인 사용을 고민하게 되었고 그 결과 싱글톤 패턴이 왜 필요한지 어느정도 감을 갖게 되었다.
1)싱글톤 패턴이란?
- 어떤 클래스의 인스턴스가 하나임을 보장하는 전역에서 접근 가능한 디자인 패턴
- 처음부터 끝까지 한 번의 인스턴스를 생성함으로서 메모리의 효율적인 사용을 가능하게 함
2)왜 필요한데?
사실 왜 필요한지가 잘 납득이 안되어서 처음에는 이해가 잘 안되었다. 클래스의 인스턴스가 하나임을 보장하면 뭘 할 수 있는가에 관한 의문이 들었기 때문이다. 쉽게 얘기하면 데이터 베이스를 수정할 수 있는 인스턴스가 여러가지라면 어떨까? 당연히 문제가 생길것이다. 그러한 연유로 싱글톤 패턴을 사용한다.
3)어떻게 사용해?
이를 고민하기 전에 좀 더 익숙한 자바 코드로 한번 보자.
public class DBHelper {
private static DBHelper instance;
private DBHelper() {}
public static DBHelper getInstance() {
if(instance ==null) {
instance = new DBHelper();
}
return instance;
}
}
외부에서 인스턴스 못만들게 private으로 만들어 놓고
인스턴스가 있으면 그냥 리턴해주고 없으면 만들어서 리턴해준다. 즉 인스턴스가 무조건 하나 밖에 만들어 질 수 없는 구조이다
이를 코틀린에서는 object라는 키워드로 간단하게 지원해 준다.
https://developer.android.com/reference/java/lang/Object
Object | Android Developers
android.net.wifi.hotspot2.omadm
developer.android.com
object DBHandler {}
val dbHandler = DBHandler
참 간단하다. 이를 통한 싱글톤 패턴의 구현은 문제가 있다.
1)파라미터가 없는 인스턴스만 생성이 가능하다.
2)메모리 낭비가 심하다.
1번은 뭐 이해되는데 2번은 무슨말이냐?
자바 코드의경우 getInstance()가 실행될때 인스턴스가 만들어진다. 그에 비해 아래 코틀린은 프로세스가 시작 될 때 만들어진다.
즉 인스턴스를 쓰지 않고 있을때도 만들어진다는 것이다.
우리는 두가지 문제를 해결해볼 것이다
1)
class DBHandler private constructor(context:Context) {
companion object {
private var instance : DBHanlder? = null
fun getInstance(context:Context) =
instace ?: DBHandler(context).also {
instance = it
}
}
}
1번 문제는 간단하게 해결 할 수 있다.
그냥 구현하면 된다. 자바의 코드와 동일한 효과를 낸다.
근데 여기서 우리는 하나의 모르는 키워드를 하나 더 만나게 된다.
companion object 가 뭐지?
1-1) companion object vs object
앞서 얘기했듯이 object 키워드는 싱글톤 패턴을 만들어 준다.
근데 코틀린에서는 static 키워드를 지원하지 않는다. 그래서 클래스 인스턴스 없이 함수의 내부에 접근하고 싶을때 companion object를 쓴다
2)
이 역시 lazy 키워드를 통해 간단하게 해결 가능하다.
class DBHelper private constructor() {
companion object {
val instance:DBHelper by lazy {~~~~~}
}
}
4)또 다른 문제가 생겼어
위에서 구현한 싱글톤 패턴의 또 다른 문제가 있다. 쓰레드가 하나일 때만 쓰레드 세이프를 보장한다는 거다.
즉 쓰레드가 동시에 인스턴스를 생성하는 경우에는 여러개의 인스턴스가 만들어 질 수 있다는 것이다.
class DBHandler private constructor (context:Context) {
companion object {
@Volatile
private var instance:DBHandler?= null
fun getInstance(context:Context) =
instacne?:synchronized(DBHelper::class.java) {
instance ?: DBHandler(context).also {
instance = it
}
}
}
}
위와 같이 구현이 가능하다. null check를 두번 함으로써 thread-safe를 보장한다.
4-1)근데 Volatile 이 뭔데
휘발성이 있는 뭐 이런뜻인거 다 알긴아는데 저게 무슨 키워든데?
이는 구조를 좀 알아야한다
일반적으로 쓰레드는 메인메모리에 접근할때 내부 성능향상을 위해 cpu캐시에 저장하게 된다.
근데 쓰레드가 두개 이상이라면 쓰레드 간의 접근 시간의 차이로 이미 인스턴스가 만들어졌음에도 cpu에 이를 전달하지 못하여
다른 쓰레드가 또 인스턴스를 만들게 된다. 이를 방지하기 위한 키워드로, 메인 메모리로부터 읽어온 값을 캐시에 저장하지 않고
메인메모리에 바로 저장한다.
근데 이 방법이 찾아보니까 여러가지 말이 많은거 같다
https://herdin.github.io/2020/12/25/about-double-check-locking
Epu Baal – developer from pamukkale
developer from pamukkale
herdin.github.io
대부분의 경우 holder를 통해 이를 보강하긴 하는데 이는 말이 많은거 같다. 본인이 선택해야 할 문제이다.
참고
https://jaejong.tistory.com/105
[Kotlin] 코틀린 기본 - object / Companion Object(동반 객체)
Kotlin - object 키워드 + Companion Object (동반 객체) Kotlin object 키워드 object는 흔히 JAVA에서 사용하는 무명 내부 클래스(anonymous inner class) 처럼 사용할 수 있습니다 object 키워드는 클래스를..
jaejong.tistory.com
https://herdin.github.io/2020/12/25/about-double-check-locking
Epu Baal – developer from pamukkale
developer from pamukkale
herdin.github.io
https://www.charlezz.com/?p=45959
코틀린/자바의 volatile에 대해서 | 찰스의 안드로이드
volatile이란? 자바의 volatile 키워드 또는 코틀린의 @Volatile 애노테이션을 변수 선언시 지정할 수 있다. 사전적 의미로는 '휘발성의'라는 뜻을 가지며, 변수 선언시 volatile을 지정하면 값을 메인 메
www.charlezz.com
[Kotlin] object 를 이용한 싱글톤 패턴 구현
개발을 하다보면 객체에 대한 하나의 인스턴스만 필요할 때, 하나의 인스턴스를 재사용하기 위해 싱글톤 패턴을 구현해야 할 일이 생긴다. *싱글톤 패턴 : 객체의 인스턴스를 1개만 생성하여 계
kotlinworld.com
https://www.inflearn.com/course/알기쉬운-modern-android
냉동코더의 알기 쉬운 Modern Android Development 입문 - 인프런 | 강의
이 강의의 목적은 Android Jetpack을 중심으로 한 안드로이드 라이브러리의 동작 원리를 이해하고 앱에 적용하는 법을 알기 쉽게 전달하는 것입니다., - 강의 소개 | 인프런...
www.inflearn.com
'프로그래밍 > 안드로이드' 카테고리의 다른 글
리사이클러뷰 갱신(리스트어댑터) - 안드로이드 (0) | 2022.11.02 |
---|---|
SMTP로 메일보내기 - 안드로이드 (2) | 2022.10.11 |
프레그먼트와 네비게이션 바 - 안드로이드 (0) | 2022.09.21 |
코루틴 - 안드로이드 (0) | 2022.09.13 |
제트팩1 - 안드로이드 (0) | 2022.09.06 |