Sam Story

Singletone Pattern (싱글톤 패턴) 본문

개발지식

Singletone Pattern (싱글톤 패턴)

Sam H 2024. 12. 6. 18:56

오늘은 싱글톤 패턴에 대해서 포스팅 해보려 한다.

 

개발 초창기만 하더라도 자바를 이용해서 static 객체를 만드는게 굉장히 조심스러웠다.

이 객체를 얼마나 호출해서 사용하는지 , 싱글톤 객체로 만드는게 더 효율적인지

기준이 안잡혀 있기 때문에 더 혼란스러웠던것 같다.

 

지금도 완벽하게 이해하고 있지는 않지만 싱글톤 패턴에 대해 좀 더 공부해보고

기준을 좀 더 명확히 해보자.

 

 

싱글톤 패턴이란?

클래스의 인스턴스를 하나만 생성하여 전역적으로 접근할 수 있도록 보장하는 디자인 패턴이다.

주로 공유 자원 관리, 설정 관리, 로그 관리 등과 같은 경우에 사용한다.

 

기존에 진행했던 FitFit 프로젝트에도 이 싱글톤 패턴이 적용되어 있다.

적용 방법 자체는 좀 잘못된 방향으로 흘러갔지만

적용하고 보니 얼마나 유용한지 느낄 수 있었던 기회였다.

 

이러한 싱글톤 패턴은 간단히 설명해보자면

싱글톤 패턴은 객체의 인스턴스를 한개만 생성되게 하는 패턴이다.

 

이 한개의 인스턴스를 전역으로 사용할 수 있는것이다.

 

 

왜 싱글톤 패턴을 사용하는가?

1. 전역 상태 관리: 여러 객체에서 동일한 인스턴스를 공유하기 때문에 상태 관리가 용이하다.

 

2. 메모리 절약: 인스턴스를 하나만 생성하므로 메모리 낭비를 방지할 수 있다.

 

만약 여러 class에서 사용되는 객체가 있는 경우

매번 그 객체를 새로 만들어서 사용하는 것보다는 모든 class에서 사용할 수 있는

객체를 만들어서 사용하는게 효율적이기 때문에 싱글톤 패턴을 사용하는 것이다.

 

 

예제를 통해서 좀 더 쉽게 알아보자.

 

예제

오늘의 예제는 실제 FitFit 에서 적용한 사례를 예제코드로 작성해 준비했다.

SharedPreferences 객체를 싱글톤 객체로 만들어

모든 Activity에서 별도에 SharedPreferences 객체를 만들 필요없이 호출하는 예제이다.

 

먼저 Application을 상속받는 class를 하나 구현 후

그 class에서 SharedPreferences 객체를 Companion Object로 만들어 보자.

 

MyApplication class

package com.example.singletoneexample

import android.app.Application
import android.content.Context
import android.content.SharedPreferences

class MyApplication: Application() {
    // compaino object -> java의 static과 같은역할
    companion object {
        lateinit var sharedPreferences: SharedPreferences
    }

    override fun onCreate() {
        super.onCreate()
        // sharedPrefernences 객체 초기화
        sharedPreferences = applicationContext.getSharedPreferences("data", Context.MODE_PRIVATE)
    }
}

 

 

위 코드에서 특이한 점이라면 onCreate() 메서드를 호출하고 있다는 것이다.

그렇다면 이 onCreate() 메서드를 어느 시점에 호출해야 하는가.

 

어플리케이션이 실행될 때 이 코드를 먼저 실행할 수 있게끔

Manifests에 추가해준다.

 

Manifests

    <application
        android:name=".MyApplication"
        ...

 

 

위처럼 Manifests에 추가해주면 어플리케이션이 실행할 때 MyApplication class 코드를

실행하게 되고 onCreate() 메서드를 호출하면서 SharedPreferences 객체를 초기화 하게 되는것이다.

 

간단하게 텍스트뷰에 SharedPreferences에 저장된 데이터를 띄워주고

데이터를 저장하는 레이아웃으로 짜보았다.

 

MainActivity layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    // Shared에 저장된 값을 띄워주는 TextView
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

    // Shared에 저장할 String값을 입력하는 EditText
    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="저장할 값을 입력해 주세요."
        android:layout_marginHorizontal="20dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        app:layout_constraintBottom_toBottomOf="parent"/>

    // Shared에 데이터 저장하는 버튼
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="값 저장"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/editText"/>

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

MainActivity

package com.example.singletoneexample

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView

class MainActivity : AppCompatActivity() {

    lateinit var editText: EditText
    lateinit var textView: TextView
    lateinit var button: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        editText = findViewById(R.id.editText)
        textView = findViewById(R.id.textView)
        button = findViewById(R.id.button)

        val text = MyApplication.sharedPreferences.getString("data","")

        if (text.equals("")) {
            textView.text = "저장된 텍스트가 없습니다."
        } else {
            textView.text = text
        }

        // 버튼을 누르면 editText에 입력한 값을 Shared에 저장.
        button.setOnClickListener {
            val editor = MyApplication.sharedPreferences.edit()
            editor.putString("data",editText.text.toString())
            editor.apply()
            textView.text = editText.text.toString()
        }
    }
}

 

 

실행결과

실행결과

 

위 EditText에 값을 입력 후

값 저장 버튼을 누르게 되면

 

실행결과

실행결과

 

위 상태에서 SharedPreferences에 값이 저장되어 있다면

어플리케이션을 종료 후 재시작해도 데이터가 남아있을것이다.

 

 

어플리케이션 종료 후 재시작 결과

실행결과

 

간단한 예제로 Singletone Pattern을 안드로이드에 적용해 보았는데

핵심은 Singleton Pattern으로 만든 인스턴스는 모든 class에서 사용할 수 있다는 것이다.

 

Room 라이브러리를 아직 제대로 다뤄보지는 않았지만

내부 데이터베이스를 이용해야 하는 상황이라면 Room 객체도

싱글톤으로 만들어 다루지 않을까 싶다.

 

이러한 싱글톤 패턴을 적용하면 메모리를 굉장히 효율적으로

절약할 수 있다고 생각한다.

 

오늘의 예제 github

https://github.com/nam-su/SingletoneExample

 

GitHub - nam-su/SingletoneExample

Contribute to nam-su/SingletoneExample development by creating an account on GitHub.

github.com

 

'개발지식' 카테고리의 다른 글

Observer 패턴  (0) 2025.02.12
자바 버전에 대하여 (8 , 11 , 17)  (1) 2024.12.02
객체지향 프로그래밍 SOLID 원칙  (1) 2024.09.24
객체지향 프로그래밍  (5) 2024.09.23
REST,REST API  (0) 2024.08.21