<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>day_park_94.log</title>
        <link>https://velog.io/</link>
        <description>#모바일 #Android #Flutter #개발문화</description>
        <lastBuildDate>Fri, 19 May 2023 06:53:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>day_park_94.log</title>
            <url>https://velog.velcdn.com/images/day_park_94/profile/87adef26-df02-428d-9080-9787765a8406/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. day_park_94.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/day_park_94" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[싱글톤 패턴(Singletone Pattern)은 언제나 옳다?]]></title>
            <link>https://velog.io/@day_park_94/%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4Singletone-Pattern%EC%9D%80-%EC%96%B8%EC%A0%9C%EB%82%98-%EC%98%B3%EB%8B%A4</link>
            <guid>https://velog.io/@day_park_94/%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4Singletone-Pattern%EC%9D%80-%EC%96%B8%EC%A0%9C%EB%82%98-%EC%98%B3%EB%8B%A4</guid>
            <pubDate>Fri, 19 May 2023 06:53:02 GMT</pubDate>
            <description><![CDATA[<h1 id="개요">개요</h1>
<p>A:&#39;<strong>싱글톤 패턴</strong>은 무엇인가요?&#39;
B: &#39;객체를 단 하나의 인스턴스로 생성하여 하나의 인스턴스를 프로세스가 돌아가는 동안 전역에서 접근 할 수 있는 <strong>디자인 패턴</strong>입니다.&#39;
A: &#39;이 패턴의 위험성에 대해 말씀해주세요.&#39;
B: &#39;...&#39;</p>
<p>개발자라면 싱글톤 패턴(Singletone Pattern)을 사용해봤는지 물어봤을 때 &#39;네&#39;라는 말을 하겠지만,
싱글톤 패턴의 위험성을 고민해봤는지 물어봤을 때 모두 &#39;네&#39;라는 말을 하진 않습니다.</p>
<p>해당 글은 싱글톤에 대한 개인적인 고찰을 기록하기 위해 남겨둡니다.</p>
<hr>
<h1 id="싱글톤이란">싱글톤이란?</h1>
<p>싱글톤 패턴은 언어별 구현 형태가 다르지만서도 정의는 동일합니다.</p>
<p>&#39;<strong>Head First:Design Pattern</strong>&#39;에서는 싱글톤을 아래와 같이 정의를 합니다.</p>
<blockquote>
<p>싱글톤 패턴(Singletone pattern)은 해당 클래스의 인스턴스가 하나만 만들어지고, 어디서든 그 인스턴스에 접근할 수 있도록 하기 위한 패턴이다.</p>
</blockquote>
<p align="center">
  <img src="https://velog.velcdn.com/images/day_park_94/post/7e477eee-85ae-44ec-b6dd-4cb77a5b7945/image.png" alt="text" width="number" />
  싱글톤 패턴의 다이어 그램
</p>

<hr>
<h1 id="개발자는-왜-싱글톤-패턴을-사용할까">개발자는 왜 싱글톤 패턴을 사용할까?</h1>
<p>위 내용에서 정의한대로 싱글톤 패턴은 전역 상태로 메모리(Data) 영역에 저장되어 있는 객체의 인스턴스입니다. </p>
<p>** 왜 개발자들은 싱글톤 패턴을 쓰는걸까요?</p>
<ol>
<li><p><strong>생성 코스트 절감</strong></p>
<p> 객체를 생성하게 되면 메모리(Heap) 영역에서 리소스를 할당합니다. 동일 리소스를 반복적으로 여러 객체에서 접근해서 사용해야 하는 경우나 한번 생성할 때 발생하는 코스트가 높은 경우, 싱글톤 패턴을 이용해서 필요한 공유 객체를 메모리(Data) 영역에 한번만 생성하여 성능상 이점을 얻을 수 있습니다.</p>
</li>
<li><p><strong>공유 리소스 관리</strong></p>
<p> 싱글톤 패턴은 여러 객체가 공유하는 리소스를 효율적으로 관리할 수 있습니다. 데이터베이스 연결, 로깅, 설정 등 전역으로 선언하여 여러 객체에서 접근이 가능하고 일관된 상태를 유지할 수 있습니다. </p>
</li>
<li><p>*<em>공유 리소스 접근 *</em></p>
<p> 여러 객체에서 동시에 접근하여 사용할 때, 실제 인스턴스화된 객체는 하나이기 때문에 별다른 동기화 작업 없이 데이터의 무결성을 유지할 수 있습니다.(첫 생성 경우 제외)</p>
</li>
</ol>
<p>싱글톤 패턴은 위와 같은 장점이 있지만, 과도한 사용은 의존성과 결합도를 높일 수 있고 테스트하기 어려워질 수 있습니다. 아래에서 싱글톤의 단점과 위험성에 대해 이야기를 하겠습니다.</p>
<hr>
<h1 id="문제점">문제점</h1>
<p>싱글톤 패턴은 언뜻 사용하기에는 편리성이 좋습니다. 그렇지만 사용하는 방법과 호출하는 방법 등에서 오남용으로 발생할 수 있는 문제들이 있습니다.</p>
<p>다른 클래스에서 전역 객체를 호출한다는 것은 클래스의 인스턴스 간 결합도가 높아져서 <em>&#39;개발-폐쇄 원칙(OCP, Open Close Principle)&#39;</em>에 위배가 됩니다. </p>
<p>그리고, 멀티 스레드 환경에서 동기화 처리가 되지 않을 때, 싱글톤 패턴의 정의와 같이 하나가 아닌 n개의 인스턴스가 생성될 수 있습니다. 그렇게 되었을 때 데이터의 무결성이 무너지고 메모리 관리에도 치명적인 이슈가 발생하게 됩니다.</p>
<pre><code>class Singleton private constructor() {
    init {
        println(&quot;Singleton 인스턴스 생성&quot;)
    }

    companion object {
        // getInstance를 호출 할 때마다 새로운 객체를 인스턴스화함.
        fun getInstance(): Singleton {
            return Singleton()
        }
    }
}

fun main() {
    // 신규 인스턴스가 호출하는 만큼 생성 
    val singleton1 = Singleton.getInstance()
    val singleton2 = Singleton.getInstance()

    if (singleton1 == singleton2) {
        println(&quot;같은 인스턴스입니다.&quot;)
    } else {
        println(&quot;다른 인스턴스입니다.&quot;)
    }
}</code></pre><hr>
<h1 id="반영-방법">반영 방법</h1>
<ul>
<li><code>synchronized</code> 키워드를 이용해서 thread-safety를 보장합니다. 
단점) 키워드 자체가 많은 cost를 필요하기 때문에 성능 저하로 이어질 수 있습니다.
그리고 인스턴스의 null 상태를 더블 체크하는 로직은 호출마다 호출되기 때문에 위와 마찬가지로 성능 저하로 이어질 수 있습니다.</li>
</ul>
<pre><code>class SynchonizedSingleton private constructor() {
    init {
        println(&quot;SynchonizedSingleton 인스턴스 생성&quot;)
    }

    companion object {
        @Volatile
        private var instance: SynchonizedSingleton? = null

        @Synchronized
        fun getInstance(): SynchonizedSingleton {
            if (instance == null) {
                instance = Singleton()
            }
            return instance!!
        }
    }
}</code></pre><ul>
<li><p>lazy 기법을 통해 처음 호출할 때 인스턴스화하고 조건문으로 인스턴스화가 제어됩니다.
단점) Multi-Thread 상황에서 동시 호출 처리가 되면 n개의 인스턴스가 생성될 수 있습니다.</p>
<pre><code>class LazySingleton private constructor() {
  init {
      println(&quot;LazySingleton 인스턴스 생성&quot;)
  }

  companion object {
      val instance: LazySingleton by lazy {
          LazySingleton()
      }
  }
}</code></pre></li>
<li><p>Holder를 통해 Class가 로드되는 시점을 이용하는 방법입니다. JVM의 특성을 최대한 활용한 기법으로 JVM이 클래스 초기화 과정에서 원자성을 보장하게 됩니다.</p>
</li>
</ul>
<pre><code>class HolderSingleton private constructor() {
    init {
        println(&quot;HolderSingleton 인스턴스 생성&quot;)
    }

    companion object {
        private val instanceHolder = Holder.instance

        val instance: HolderSingleton
            get() = instanceHolder
    }

    private object Holder {
        val instance = HolderSingleton()
    }
}</code></pre>]]></description>
        </item>
    </channel>
</rss>