<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jeanine.log</title>
        <link>https://velog.io/</link>
        <description>Grow up everyday</description>
        <lastBuildDate>Sat, 03 Jun 2023 10:24:01 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jeanine.log</title>
            <url>https://images.velog.io/images/jieun_han/profile/41304b3b-2207-4dee-a25b-636fd3022def/social.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jeanine.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jieun_han" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[iOS 개발] Xcode 시작하기]]></title>
            <link>https://velog.io/@jieun_han/iOS-%EA%B0%9C%EB%B0%9C-Xcode-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jieun_han/iOS-%EA%B0%9C%EB%B0%9C-Xcode-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 03 Jun 2023 10:24:01 GMT</pubDate>
            <description><![CDATA[<h1 id="0-주저리">0. 주저리</h1>
<p>예전부터 iOS 개발을 배우고 싶었는데 <del>(그 핑계로 맥북까지 산)</del>
상황이 여의치 않아 이제서야 하나씩 배워보고자 한다.</p>
<p>이 시리즈는 iOS 개발을 한 번도 해보지 않은 현역 개발자의 iOS 개발 공부 여정을 담았다.</p>
<h1 id="1-환경설정">1. 환경설정</h1>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/6680cd8e-21bb-4fa4-96a4-550355366d94/image.png" alt=""></p>
<ul>
<li>제일 먼저 Create a new Xcode project를 눌러 새로운 프로젝트를 생성해준다.</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/c55c032c-748d-41a4-aad9-ccdf0041e7db/image.png" alt=""></p>
<ul>
<li>우선 나는 앱 개발을 하고 싶기에 App을 선택해주었다.</li>
</ul>
<hr>
<ul>
<li>참고로 제일 상단에 iOS를 클릭하면 다양한 Application들이 나오는데, 그중에서 iMessage App이나 Sticker Pack App이 있었다.
<img src="https://velog.velcdn.com/images/jieun_han/post/29a87c0b-5cf4-415a-8839-6ad93b9ab689/image.jpeg" alt=""></li>
<li>이렇게 iMessage를 보낼 때 쓰일 수 있는 App인가보다 (이렇게 게임까지 가능한지는 몰랐다...!)</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/3b94469f-de95-444e-904f-af07986221c5/image.png" alt=""></p>
<ul>
<li>이제 여기에 필요한 내용을 넣어준다.</li>
<li>Organization Identifier의 경우에는 보통 회사의 도메인을 거꾸로 쓴다고 한다.</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/25f89d79-f745-4684-9bfb-7c3baf666be6/image.png" alt=""></p>
<ul>
<li>그러면 어디에 프로젝트를 저장할지 결정해야 하는데, 나는 일단 혼자 공부하는 거라 Git repository를 생성하지는 않았다 (Source Control 박스 uncheck)</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/069bc64a-21ea-4503-b74a-e74ac9c25eb2/image.png" alt=""></p>
<ul>
<li>그러면 이렇게 개발할 수 있는 프로젝트가 생성된다.</li>
</ul>
<h1 id="2-화면-구성">2. 화면 구성</h1>
<h2 id="1-content-view">1) Content View</h2>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/d04b5778-2462-4025-9f3a-7533fcff8908/image.png" alt=""></p>
<ul>
<li>제일 먼저 Content View에서는 내가 짠 코드가 실제로 디바이스에서는 어떻게 보이는지 확인할 수 있다.</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/a977127e-802c-4662-98fe-50784df6de5a/image.png" alt=""></p>
<ul>
<li><p>참고로 전체 화면 오른쪽 상단에 위와 같은 아이콘이 있는데</p>
<ul>
<li>두 번째 아이콘: 화면 구성을 바꿀 수 있다 (Canvas를 uncheck하면 Content View가 사라진다)</li>
<li>세 번째 아이콘: 현재 화면 구성대로 똑같은 화면을 더 추가한다</li>
</ul>
</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/f1c9837a-8441-43ee-b320-114805bd8979/image.png" alt=""></p>
<ul>
<li><p>Content View의 오른쪽 하단에 보면 이러한 아이콘이 있는데</p>
<ul>
<li>(-)기호: 디바이스 크기를 줄인다</li>
<li>(1)기호: 느낌상 1배율로 보여주는 것 같은데 확실하지 않다</li>
<li>(□)기호: 화면에 꽉차게 보여준다</li>
<li>(+)기호: 디바이스 크기를 늘린다</li>
</ul>
</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/f87d6dd2-e397-4985-aea2-b760d7228c9a/image.png" alt=""></p>
<ul>
<li><p>Content View의 왼쪽 하단에 보면 이러한 아이콘들이 있는데</p>
<ul>
<li>첫 번째 아이콘: 기본적으로 보여지는 화면</li>
<li>두 번째 아이콘: 디바이스에서 각 요소를 클릭해서 속성을 확인하거나 바꿀 수 있다</li>
<li>세 번째 아이콘:
  -Color Scheme Variants: Light모드와 Dark모드를 한눈에 볼 수 있다
  -Orientation Variants: 디바이스를 돌렸을 때 모습까지도 한눈에 볼 수 있다
  -Dynamic Type Variants: 다양한 디바이스 모습을 한눈에 볼 수 있다</li>
</ul>
</li>
</ul>
<h2 id="2-navigator">2) Navigator</h2>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/33da6c5c-ecbd-4620-b0d0-fade52be47c4/image.png" alt=""></p>
<ul>
<li><p>프로젝트가 생성되면 자동으로 만들어지는 파일들을 한눈에 볼 수 있다.</p>
</li>
<li><p>구성</p>
<ul>
<li>Assets: 앱에 들어갈 색깔, 이미지 등을 설정할 수 있다</li>
<li>ContentView: 위에서 설명한 미리보기다</li>
<li>SampleTests: 기능적인 테스트를 하는 용도인 것 같다 (나중에 공부해볼 것)</li>
<li>SampleUITests: UI 테스트를 하는 용도인 것 같다 (나중에 공부해볼 것)</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>ContentView 파일을 선택한다
<img src="https://velog.velcdn.com/images/jieun_han/post/0aa8ac3e-babc-40a6-8d18-d329d040dcec/image.png" alt=""></li>
<li>오른쪽 상단에 + 아이콘을 누르면 다양한 요소들을 선택할 수 있는데
<img src="https://velog.velcdn.com/images/jieun_han/post/10fa98b8-6b70-4179-9cb7-e11b79ec2fba/image.png" alt=""></li>
<li>그 중에서 원하는 아이콘을 선택해 코드로 드래그를 해준다
<img src="https://velog.velcdn.com/images/jieun_han/post/b72468b2-b46e-4490-99d9-6445c84d2f3c/image.png" alt=""></li>
<li>그러면 이렇게 버튼이 추가된다</li>
<li>이런 식으로 UI 요소를 추가할 수 있는 것 같다! (상당히 편리한듯🤔)</li>
</ul>
<hr>
<p>다음 번에는 UI 작업을 해보겠다🔜</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 5464번]]></title>
            <link>https://velog.io/@jieun_han/%EB%B0%B1%EC%A4%80-5464%EB%B2%88</link>
            <guid>https://velog.io/@jieun_han/%EB%B0%B1%EC%A4%80-5464%EB%B2%88</guid>
            <pubDate>Mon, 07 Nov 2022 02:44:32 GMT</pubDate>
            <description><![CDATA[<p>💻 C++ 기반</p>
<blockquote>
<p>주차장
<a href="https://www.acmicpc.net/problem/5464">https://www.acmicpc.net/problem/5464</a></p>
</blockquote>
<p>✔️ 문제에 나와있는 대로 구현하면 됨
✔️ 차가 빠질 때 요금 산정</p>
<hr>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;queue&gt;

#define MAXN 100
#define MAXM 2001

using namespace std;

int N, M;
bool isTaken[MAXN + 10];
int parkingFee[MAXN + 10];
int carsWeight[MAXM + 10];
int parkingPlace[MAXM + 10];

int getParkingPlace()
{
    for (int i = 1; i &lt;= N; i++)
    {
        if (!isTaken[i])
        {
            return i;
        }
    }
    return 0;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    cin &gt;&gt; N &gt;&gt; M;
    for (int i = 1; i &lt;= N; i++)
    {
        cin &gt;&gt; parkingFee[i];
    }

    for (int i = 1; i &lt;= M; i++)
    {
        cin &gt;&gt; carsWeight[i];
    }

    int total = 0;
    queue&lt;int&gt; waitingQ;
    for (int i = 0; i &lt; 2 * M; i++)
    {
        int input;
        cin &gt;&gt; input;
        if (input &gt; 0)
        {
            int place = getParkingPlace();
            if (place != 0)
            {
                parkingPlace[input] = place;
                isTaken[place] = true;
            }
            else
            {
                waitingQ.push(input);
            }
        }
        else
        {
            int carNum = (-1) * input;
            int place = parkingPlace[carNum];
            total += parkingFee[place] * carsWeight[carNum];
            parkingPlace[carNum] = 0;
            isTaken[place] = false;

            if (!waitingQ.empty())
            {
                parkingPlace[waitingQ.front()] = place;
                isTaken[place] = true;
                waitingQ.pop();
            }
        }
    }
    cout &lt;&lt; total;
    return 0;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 2563번]]></title>
            <link>https://velog.io/@jieun_han/%EB%B0%B1%EC%A4%80-2563%EB%B2%88</link>
            <guid>https://velog.io/@jieun_han/%EB%B0%B1%EC%A4%80-2563%EB%B2%88</guid>
            <pubDate>Mon, 07 Nov 2022 01:56:20 GMT</pubDate>
            <description><![CDATA[<p>💻 C++ 기반</p>
<blockquote>
<p>색종이
<a href="https://www.acmicpc.net/problem/2563">https://www.acmicpc.net/problem/2563</a></p>
</blockquote>
<p>✔️ 색종이의 영역을 배열에 표시 (True: 색종이 있음, False: 색종이 없음)</p>
<hr>
<pre><code class="language-cpp">#include &lt;iostream&gt;

#define MAX 100

using namespace std;

bool paper[MAX + 10][MAX + 10];
int N;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    cin &gt;&gt; N;
    while (N--)
    {
        int x, y;
        cin &gt;&gt; x &gt;&gt; y;
        for (int i = 0; i &lt; 10; i++)
        {
            for (int j = 0; j &lt; 10; j++)
            {
                paper[y + i][x + j] = true;
            }
        }
    }

    int ans = 0;
    for (int i = 0; i &lt; 100; i++)
    {
        for (int j = 0; j &lt; 100; j++)
        {
            if (paper[i][j])
            {
                ans++;
            }
        }
    }

    cout &lt;&lt; ans;
    return 0;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 가장 큰 수]]></title>
            <link>https://velog.io/@jieun_han/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B0%80%EC%9E%A5-%ED%81%B0-%EC%88%98</link>
            <guid>https://velog.io/@jieun_han/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B0%80%EC%9E%A5-%ED%81%B0-%EC%88%98</guid>
            <pubDate>Wed, 03 Aug 2022 07:59:47 GMT</pubDate>
            <description><![CDATA[<p>💻 C++ 기반</p>
<blockquote>
<p>코딩테스트 연습 - 가장 큰 수
<a href="https://school.programmers.co.kr/learn/courses/30/lessons/42746">https://school.programmers.co.kr/learn/courses/30/lessons/42746</a></p>
</blockquote>
<p>✔️ 정렬을 해야 하는 배열의 길이가 최대 100,000이므로 시간 복잡도가 O(N^2)인 정렬을 쓰면 안된다.
✔️ C++ 라이브러리 중에 &#60;algorithm&#62;의 sort 함수를 사용하면 시간 복잡도가 O(NlogN)이다.
✔️ 입력으로 주어지는 배열에는 같은 숫자가 중복해서 들어갈 수 있다.
✔️ 입력으로 주어지는 배열에 다 0만 있다면 답은 0이 되어야 한다. (0000… 아님!)</p>
<hr>
<pre><code class="language-cpp">#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;

using namespace std;

bool compare(int num1, int num2)
{
    string str1 = to_string(num1);
    string str2 = to_string(num2);

    string temp1 = &quot;&quot;;
    temp1 += str1;
    temp1 += str2;

    string temp2 = &quot;&quot;;
    temp2 += str2;
    temp2 += str1;

    int len = str1.length() + str2.length();

    for (int i = 0; i &lt; len; i++)
    {
        if (temp1[i] &gt; temp2[i])
        {
            return true;
        }
        else if (temp1[i] &lt; temp2[i])
        {
            return false;
        }
    }

    return false;
}

string solution(vector&lt;int&gt; numbers) {
    string answer = &quot;&quot;;

    sort(numbers.begin(), numbers.end(), compare);

    for (int i = 0; i &lt; numbers.size(); i++)
    {
        if (answer == &quot;0&quot; &amp;&amp; numbers[i] == 0)
        {
            answer = &quot;0&quot;;
        }
        else
        {
           answer += to_string(numbers[i]); 
        }
    }

    return answer;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] viewBinding]]></title>
            <link>https://velog.io/@jieun_han/Android-viewBinding</link>
            <guid>https://velog.io/@jieun_han/Android-viewBinding</guid>
            <pubDate>Fri, 22 Jul 2022 06:12:29 GMT</pubDate>
            <description><![CDATA[<h1 id="1-설정">1. 설정</h1>
<ul>
<li>build.gradle (Module)에 아래 코드 추가</li>
</ul>
<pre><code class="language-kotlin">android {
        ...
        viewBinding {
            enabled = true
        }
    }
</code></pre>
<h1 id="2-사용">2. 사용</h1>
<ul>
<li>MainActivity.kt에 아래 코드 추가<ul>
<li>해당하는 xml 파일에 따라서 이름이 바뀜 (e.g. activity_main.xml -&gt; ActivityMainBinding)</li>
</ul>
</li>
</ul>
<pre><code class="language-kotlin">    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        binding.apply {
            btnSubmit.setOnClickListener {
                val name = etName.text.toString()
                tvMessage.text = &quot;Hello! $name&quot;
                etName.setText(&quot;&quot;)
            }
        }
    }</code></pre>
<h1 id="3-findviewbyid에-비해-좋은점">3. findViewById에 비해 좋은점</h1>
<p>① View를 직접 참조하기 때문에 유효하지 않은 View ID로 인해 null 포인터 예외가 발생할 위험이 없음</p>
<p>② 각 바인딩 클래스에 있는 필드의 유형이 XML 파일에서 참조하는 뷰와 일치하므로 클래스 변환 예외가 발생할 위험이 없음</p>
<hr>
<p>[공식 문서 참고]</p>
<ol>
<li><a href="https://developer.android.com/topic/libraries/view-binding?hl=ko">뷰 결합</a></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] ViewModel]]></title>
            <link>https://velog.io/@jieun_han/Android-Studio-ViewModel</link>
            <guid>https://velog.io/@jieun_han/Android-Studio-ViewModel</guid>
            <pubDate>Mon, 18 Jul 2022 02:56:19 GMT</pubDate>
            <description><![CDATA[<h1 id="0-개요">0. 개요</h1>
<p>앱 개발을 하다 보면, count 변수를 증가시키는 것과 같은 기능이 필요할 때가 있다.
그러나 화면을 회전시키면 수명 주기때문에 다시 데이터가 초기화된다.
이와 같이 _화면 회전과 같이 구성을 변경할 때도 데이터를 유지_하기 위해 쓰이는 개념이 <strong>ViewModel 클래스</strong>이다.</p>
<hr>
<h1 id="1-필요한-개념">1. 필요한 개념</h1>
<h3 id="①-ui-컨트롤러">① UI 컨트롤러</h3>
<p>User interface (UI) controllers serve as a connection between your UI and any business logic in your application that controls, or is instructed by, that UI.
➡ UI와 비즈니스 로직 사이를 연결해주는 역할</p>
<h3 id="②-viewmodel">② ViewModel</h3>
<ul>
<li>액티비티나 프래그먼트의 데이터를 관리하는 클래스</li>
<li>화면 전환이 이루어진 경우, 새로운 인스턴스 owner가 기존에 존재하던 ViewModel에 연결</li>
<li>LiveData의 형태로 액티비티/프래그먼트의 정보 저장 및 전송</li>
</ul>
<h3 id="③-livedata">③ LiveData</h3>
<ul>
<li>관찰 가능한 데이터 홀더 클래스</li>
<li>Observer 객체에 UI를 업데이트</li>
</ul>
<hr>
<h1 id="2-구현">2. 구현</h1>
<h2 id="1-livedata-없이-수동으로-업데이트">1) LiveData 없이 수동으로 업데이트</h2>
<h3 id="①-viewmodel-클래스-생성-mainactivitymodelkt">① ViewModel 클래스 생성 (MainActivityModel.kt)</h3>
<pre><code class="language-kotlin">class MainActivitylModel : ViewModel() {
    var count = 0

    fun updateCount() {
        count++
    }
}</code></pre>
<h3 id="②-액티비티에서-viewmodel-사용">② 액티비티에서 ViewModel 사용</h3>
<pre><code class="language-kotlin">class MainActivity : AppCompatActivity() {
    var count = 0
    private lateinit var viewModel: MainActivitylModel

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

        // this는 owner를 의미한다.
        viewModel = ViewModelProvider(this).get(MainActivitylModel::class.java)

        val textView = findViewById&lt;TextView&gt;(R.id.tvCount)
        val button = findViewById&lt;Button&gt;(R.id.btnCount)

        textView.text = viewModel.count.toString()

        button.setOnClickListener {
            viewModel.updateCount()
            textView.text = viewModel.count.toString()
        }
    }
}</code></pre>
<h2 id="2-livedata를-사용해서-자동으로-업데이트">2) LiveData를 사용해서 자동으로 업데이트</h2>
<h3 id="①-viewmodel-클래스-생성-mainactivitymodelkt-1">① ViewModel 클래스 생성 (MainActivityModel.kt)</h3>
<pre><code class="language-kotlin">class MainActivitylModel : ViewModel() {
    var count = MutableLiveData&lt;Int&gt;()

    init {
        count.value = 0
    }

    fun updateCount() {
        // value로 접근해야 한다.
        count.value = (count.value)?.plus(1)
    }
}</code></pre>
<h3 id="②-액티비티에서-viewmodel-사용-1">② 액티비티에서 ViewModel 사용</h3>
<pre><code class="language-kotlin">class MainActivity : AppCompatActivity() {
    var count = 0
    private lateinit var viewModel: MainActivitylModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewModel = ViewModelProvider(this).get(MainActivitylModel::class.java)

        val textView = findViewById&lt;TextView&gt;(R.id.tvCount)
        val button = findViewById&lt;Button&gt;(R.id.btnCount)

        // 값을 자동으로 업데이트 해준다.
        viewModel.count.observe(this, Observer {
            textView.text = it.toString()
        })

        button.setOnClickListener {
            viewModel.updateCount()
        }
    }
}</code></pre>
<hr>
<h1 id="3-수명-주기">3. 수명 주기</h1>
<ul>
<li>액티비티가 끝날 때까지 메모리에 유지</li>
<li>프래그먼트가 분리될 때까지 메모리에 유지
<img src="https://velog.velcdn.com/images/jieun_han/post/166e9255-3329-49dd-940c-88032b5ccf76/image.png" alt=""></li>
<li>위 그림을 보면, 화면 전환이 되면서 onDestroy가 실행되어도 ViewModel은 아직 유지되는 것을 볼 수 있다. </li>
</ul>
<hr>
<p>[공식 문서 참고]</p>
<ol>
<li><a href="https://developer.android.com/topic/libraries/architecture/viewmodel?hl=ko">ViewModel 개요</a></li>
<li><a href="https://developer.android.com/reference/androidx/lifecycle/ViewModel?hl=ko">ViewModel</a></li>
<li><a href="https://developer.android.com/topic/libraries/architecture/livedata?hl=ko">LiveData 개요</a></li>
</ol>
<p>[유투브 강의 참고]</p>
<p><a href="https://www.youtube.com/watch?v=BCSlZIUj18Y">Android Development(Kotlin) Full Course For Beginners 2022</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] 생성자]]></title>
            <link>https://velog.io/@jieun_han/Kotlin-%EC%83%9D%EC%84%B1%EC%9E%90</link>
            <guid>https://velog.io/@jieun_han/Kotlin-%EC%83%9D%EC%84%B1%EC%9E%90</guid>
            <pubDate>Thu, 14 Jul 2022 07:00:01 GMT</pubDate>
            <description><![CDATA[<h1 id="생성자의-종류">생성자의 종류</h1>
<h2 id="1-primary-constructor">1) Primary Constructor</h2>
<ul>
<li>class를 정의할 때 사용</li>
<li>사용 예시</li>
</ul>
<pre><code class="language-kotlin">class Person constructor(firstName: String) { /*...*/ }</code></pre>
<ul>
<li>만약 annotation이나 visibility modifier가 없으면 <em>constructor</em> 키워드 생략 가능</li>
</ul>
<pre><code class="language-kotlin">class Person(firstName: String) { /*...*/ }</code></pre>
<ul>
<li>생성자 안에 초기화 코드를 넣을 수 없으므로 초기화 코드는 init 블록에 작성 필요</li>
</ul>
<pre><code class="language-kotlin">class InitOrderDemo(name: String) {
    val firstProperty = &quot;First property: $name&quot;.also(::println)

    init {
        println(&quot;First initializer block that prints $name&quot;)
    }

    val secondProperty = &quot;Second property: ${name.length}&quot;.also(::println)

    init {
        println(&quot;Second initializer block that prints ${name.length}&quot;)
    }
}</code></pre>
<blockquote>
<p>📌 init 블록은 클래스가 생성되면 가장 먼저 실행된다.</p>
</blockquote>
<h2 id="2-secondary-constructors">2) Secondary Constructors</h2>
<ul>
<li>constructor 키워드 필요</li>
<li><em>this</em> 키워드를 통해 Primary Constructor에 delegate 필요 (Primary Constructor가 없어도 암시적으로 delegate 가능)</li>
<li>사용 예시</li>
</ul>
<pre><code class="language-kotlin">class Person(val pets: MutableList&lt;Pet&gt; = mutableListOf())

class Pet {
    constructor(owner: Person) {
        owner.pets.add(this) // adds this pet to the list of its owner&#39;s pets
    }
}</code></pre>
<h1 id="클래스-인스턴스-생성">클래스 인스턴스 생성</h1>
<ul>
<li>코틀린에서는 new 키워드 사용 X</li>
<li>constructor를 콜해서 인스턴스 생성 (아래 코드 참고)</li>
</ul>
<pre><code class="language-kotlin">val invoice = Invoice()

val customer = Customer(&quot;Joe Smith&quot;)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] 활동 수명 주기, Activity Lifecycle]]></title>
            <link>https://velog.io/@jieun_han/Android-%ED%99%9C%EB%8F%99-%EC%88%98%EB%AA%85-%EC%A3%BC%EA%B8%B0-Activity-Lifecycle</link>
            <guid>https://velog.io/@jieun_han/Android-%ED%99%9C%EB%8F%99-%EC%88%98%EB%AA%85-%EC%A3%BC%EA%B8%B0-Activity-Lifecycle</guid>
            <pubDate>Wed, 13 Jul 2022 07:50:11 GMT</pubDate>
            <description><![CDATA[<p>안드로이드 앱 개발을 할 때 필수적으로 알아야 하는 것 중에 하나가 바로 &#39;Activity Lifecycle&#39;이다.
그런데 이와 관련된 내용(공식 문서 포함)을 보면, 너무 정보가 많아 이해하기가 어렵다.
그래서 필수적인 정보들만 정리해놓고자 한다.</p>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/397a7f5c-aa80-4010-a977-7449e9cec934/image.png" alt=""></p>
<h1 id="수명-주기-콜백">수명 주기 콜백</h1>
<h2 id="1-oncreate">1. onCreate()</h2>
<ul>
<li>Activity를 생성할 때 실행</li>
<li>전체 수명 주기 동안 한 번만 발생</li>
<li>뒤이어 onStart()와 onResume()이 연달아 실행</li>
</ul>
<h2 id="2-onstart">2. onStart()</h2>
<ul>
<li>UI를 관리하는 코드를 초기화</li>
</ul>
<h2 id="3-onresume">3. onResume()</h2>
<ul>
<li>해당 Activity가 foreground에 표시</li>
<li>다른 Activity로 이동하거나, 기기 화면이 꺼지면 onPause() 실행</li>
</ul>
<h2 id="4-onpause">4. onPause()</h2>
<ul>
<li>해당 Activity가 foreground에 있지 않을 때 실행</li>
</ul>
<h2 id="5-onstop">5. onStop()</h2>
<ul>
<li>다른 Activity가 화면 전체를 차지할 때 실행</li>
</ul>
<h2 id="6-ondestroy">6. onDestroy()</h2>
<ul>
<li>사용자가 Activity를 닫을 때 실행 / 화면을 회전할 때 실행 (= 일시적으로 Activity 소멸)</li>
</ul>
<hr>
<h1 id="실제-사용-예시">실제 사용 예시</h1>
<p>MainActivity와 SecondActivity가 있다고 하자.
수명 주기 콜백을 다 override해서 로그를 찍어보면 다음과 같다.</p>
<h2 id="1-mainactivity-실행">1) MainActivity 실행</h2>
<p>MainActivity : OnCreate
MainActivity : OnStart
MainActivity : OnResume</p>
<h2 id="2-secondactivity로-이동">2) SecondActivity로 이동</h2>
<p>MainActivity : OnPause
SecondActivity : OnCreate
SecondActivity : OnStart
SecondActivity : OnResume
MainActivity : OnStop</p>
<h2 id="3-mainactivity로-돌아가기">3) MainActivity로 돌아가기</h2>
<p>SecondActivity : OnPause
MainActivity : OnRestart
MainActivity : OnStart
MainActivity : OnResume
SecondActivity : OnStop
SecondActivity : OnDestroy</p>
<blockquote>
<p>📌 onRestart()는 Activity가 정지된 후(onStop()) 다시 시작하기 전에 호출</p>
</blockquote>
<h2 id="4-mainactivity에서-화면-회전">4) MainActivity에서 화면 회전</h2>
<p>MainActivity : OnPause
MainActivity : OnStop
MainActivity : OnDestroy
MainActivity : OnCreate
MainActivity : OnStart
MainActivity : OnResume</p>
<hr>
<p>[공식 문서 참고]</p>
<ol>
<li><a href="https://developer.android.com/guide/components/activities/activity-lifecycle">활동 수명 주기에 관한 이해</a></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] Logcat]]></title>
            <link>https://velog.io/@jieun_han/Kotlin-Logcat</link>
            <guid>https://velog.io/@jieun_han/Kotlin-Logcat</guid>
            <pubDate>Wed, 13 Jul 2022 05:38:24 GMT</pubDate>
            <description><![CDATA[<p>Android Studio에서 Logcat을 사용하는 방법을 알아보자.</p>
<p>형식은 다음과 같다.
Log.i(tag, message)</p>
<pre><code class="language-kotlin">// 실제 사용 예시
Log.i(&quot;MYTAG&quot;, &quot;MainActivity : OnCreate&quot;)</code></pre>
<p>그리고 실제로 Android Studio 하단에 Logcat을 클릭한 뒤,
Info로 설정 -&gt; 돋보기가 있는 입력창에 TAG 이름 입력을 하면 내가 보고 싶은 Log만 볼 수 있다.</p>
<p>이외에도 다양한 로그 클래스들이 있다.
Log.e(String, String) (오류, Error)
Log.w(String, String) (경고, Warn)
Log.i(String, String) (정보, Info)
Log.d(String, String) (디버그, Debug)
Log.v(String, String) (상세, Verbose)</p>
<p>📍 상세 로그는 앱으로 컴파일하면 안된다. 그리고 오류, 경고, 정보 로그는 런타임에 컴파일이 된 후 사라지지 않는다.</p>
<blockquote>
<p>Log.d를 사용하는 것이 더 좋을 것 같다.</p>
</blockquote>
<hr>
<p>[공식 문서 참고]</p>
<ol>
<li><a href="https://developer.android.com/studio/debug/am-logcat?hl=ko">Logcat을 이용한 로그 작성 및 보기</a></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 다리를 지나는 트럭]]></title>
            <link>https://velog.io/@jieun_han/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8B%A4%EB%A6%AC%EB%A5%BC-%EC%A7%80%EB%82%98%EB%8A%94-%ED%8A%B8%EB%9F%AD</link>
            <guid>https://velog.io/@jieun_han/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8B%A4%EB%A6%AC%EB%A5%BC-%EC%A7%80%EB%82%98%EB%8A%94-%ED%8A%B8%EB%9F%AD</guid>
            <pubDate>Sun, 26 Jun 2022 14:32:43 GMT</pubDate>
            <description><![CDATA[<p>💻 C++ 기반</p>
<blockquote>
<p>코딩테스트 연습 - 다리를 지나는 트럭
<a href="https://programmers.co.kr/learn/courses/30/lessons/42583">https://programmers.co.kr/learn/courses/30/lessons/42583</a></p>
</blockquote>
<p>✔️ 다리를 건너는 트럭을 위한 큐(crossing_queue) &amp; 대기 트럭을 위한 큐(waiting_queue) 사용
✔️ 최대 적재량 제한때문에 다른 트럭이 다리 위로 못 올라갈 경우, crossing_queue에 0을 push해서 트럭이 움직이는 것을 표현
✔️ 대기 트럭이 하나도 없으면 crossing_queue에 -1을 push해서 종결 조건 만들어주기</p>
<hr>
<pre><code class="language-cpp">#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;queue&gt;

using namespace std;

int solution(int bridge_length, int weight, vector&lt;int&gt; truck_weights) {
    int answer = 0;

    queue&lt;int&gt; waiting_queue;
    for (int i = 0; i &lt; truck_weights.size(); i++)
    {
        waiting_queue.push(truck_weights[i]);
    }

    queue&lt;int&gt; crossing_queue;
    int cur_weight = 0;
    while (1)
    {
        if (!crossing_queue.empty() &amp;&amp; crossing_queue.front() == -1 &amp;&amp; waiting_queue.empty())
        {
            break;
        }

        while (crossing_queue.size() &lt; bridge_length)
        {
            answer++;

            if (waiting_queue.empty())
            {
                crossing_queue.push(-1);
            }
            else
            {
                if (cur_weight + waiting_queue.front() &lt;= weight)
                {
                    cur_weight += waiting_queue.front();
                    crossing_queue.push(waiting_queue.front());
                    waiting_queue.pop();
                }
                else
                {
                    crossing_queue.push(0);
                }
            }
        }
        cur_weight -= crossing_queue.front();
        crossing_queue.pop();
    }

    answer++;
    return answer;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Bean, 빈]]></title>
            <link>https://velog.io/@jieun_han/Spring-Bean-%EB%B9%88</link>
            <guid>https://velog.io/@jieun_han/Spring-Bean-%EB%B9%88</guid>
            <pubDate>Sun, 19 Jun 2022 03:05:49 GMT</pubDate>
            <description><![CDATA[<h1 id="1-bean이란">1. Bean이란?</h1>
<p>Spring 공식문서에 의하면,</p>
<p>In Spring, <strong>the objects that form the backbone of your application</strong> and that are managed by the Spring IoC (Inversion of Control) container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container.
-&gt; <strong>Spring IoC에 의해 관리되며, 애플리케이션의 중추를 이루는 객체</strong> </p>
<p>📍 Spring IoC (Inversion of Control)?
A process in which an object defines its dependencies without creating them
-&gt; 어떤 객체가 의존성을 직접 생성하지 않고도 정의할 수 있는 과정</p>
<blockquote>
<p>Bean을 등록할 때는 <strong>싱글톤</strong> (유일하게 하나만 등록해서 공유함)
-&gt; 같은 Bean이면 모두 같은 인스턴스</p>
</blockquote>
<hr>
<h1 id="2-코드로-보는-bean">2. 코드로 보는 Bean</h1>
<h2 id="1-spring-boot-프로젝트-시작">1) Spring Boot 프로젝트 시작</h2>
<ul>
<li>@SpringBootApplication: 해당 패키지에 있는 모든 Bean 탐색 (@ComponentScan 사용)</li>
</ul>
<pre><code class="language-java">@SpringBootApplication
public class BasicBeansApplication {
    public static void main(String[] args) {
        SpringApplication.run(BasicBeansApplication.class, args);

        // 생성되는 모든 Bean들을 보고 싶다면 아래처럼
        // ApplicationContext apc = SpringApplication.run(BasicBeansApplication.class, args);
        // for (String s : apc.getBeanDefinitionNames()) {
        //      System.out.pringln(s);
        // }
    }
}</code></pre>
<p>결과 화면은 아래와 같다.
<img src="https://velog.velcdn.com/images/jieun_han/post/9cc68ab2-1fae-49dd-bcf2-3f58c9759571/image.png" alt=""></p>
<h2 id="2-새로운-bean-생성">2) 새로운 Bean 생성</h2>
<ul>
<li><p>at(@) annotation 사용</p>
</li>
<li><p><strong>@Component</strong>: 이걸 선언하면 Bean으로 인식되고, @ComponentScan에 의해 인식됨</p>
<ul>
<li>이름을 지정해주고 싶다면, @Component(value=&quot;mycomponent&quot;)</li>
<li>개발자가 직접 작성한 클래스를 Bean으로 등록하려 할 때 사용</li>
<li>하위 어노테이션: @Service, @Controller, @Repository</li>
<li>사용 예시는 아래 코드 참고</li>
</ul>
</li>
</ul>
<pre><code class="language-java">@Component
public class Customer {
    private String name;
    private Address address;

    public Customer(String name, Address, address) {
        this.name = name;
        this.address = address;
    }

    // getter, setter 생략
}</code></pre>
<ul>
<li><p><strong>@Bean</strong></p>
<ul>
<li>이름을 지정해주고 싶다면, @Bean(name=&quot;myBean&quot;)</li>
<li>개발자가 직접 제어할 수 없는 외부 라이브러리를 Bean으로 등록하려 할 때 사용</li>
<li>사용 예시는 아래 코드 참고</li>
</ul>
</li>
</ul>
<pre><code class="language-java">@SpringBootApplication
public class BasicBeansApplication {
    public static void main(String[] args) {
        SpringApplication.run(BasicBeansApplication.class, args);
    }
}

// 이렇게 Bean으로 등록을 해놓으면, 원할 때에 String이 초기화됨
@Bean
public String getName() {
    return &quot;Jeanine&quot;;
}</code></pre>
<p>📍 아래와 같이 @Service, @Repository 없이 직접 Bean 등록을 할 수 있다.
(Config 파일은 @SpringBootApplication이 정의되어 있는 파일과 같은 위치에 생성)</p>
<pre><code class="language-java">@Configuration
public class SpringConfig {

    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
}</code></pre>
<h2 id="3-bean-의존성-주입">3) Bean 의존성 주입</h2>
<ul>
<li><p><strong>@Autowired</strong></p>
<ul>
<li>클래스 안에서 다른 클래스로 정의된 Bean을 사용하고 싶을 때 선언</li>
<li>객체가 여러 개라면 @Qualifier(&quot;Bean이름&quot;)를 선언</li>
<li>사용 예시는 아래 코드 참고</li>
</ul>
</li>
</ul>
<pre><code class="language-java">@Component(value=&quot;addressbean&quot;)
public class Address {
}

@Component
public class Customer {
    private String name;

    @Qualifier(&quot;addressbean&quot;)
    @Autowired
    private Address address;

    // 아래는 생략
}</code></pre>
<hr>
<h1 id="3-정리">3. 정리</h1>
<p>Spring에서 Bean이란 <strong>Spring 컨테이너에 의해 관리되는 클래스의 인스턴스</strong></p>
<hr>
<p>참고:</p>
<ul>
<li><a href="https://galid1.tistory.com/494">@Bean 어노테이션과 @Component 어노테이션(DI) - 2</a></li>
<li><a href="https://www.youtube.com/watch?v=aS9SQITRocc">Spring ultimate basics: What are Spring Beans and what is the Spring Container?</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[바킹독의 실전 알고리즘] 그리디, Greedy]]></title>
            <link>https://velog.io/@jieun_han/%EB%B0%94%ED%82%B9%EB%8F%85%EC%9D%98-%EC%8B%A4%EC%A0%84-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B7%B8%EB%A6%AC%EB%94%94-Greedy</link>
            <guid>https://velog.io/@jieun_han/%EB%B0%94%ED%82%B9%EB%8F%85%EC%9D%98-%EC%8B%A4%EC%A0%84-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B7%B8%EB%A6%AC%EB%94%94-Greedy</guid>
            <pubDate>Wed, 15 Jun 2022 09:15:34 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>그리디(Greedy)란?
<strong>지금</strong> 가장 최적인 답을 근시안적으로 택하는 알고리즘</p>
</blockquote>
<h1 id="greedy를-푸는-과정">Greedy를 푸는 과정</h1>
<ol>
<li>관찰을 통해 탐색 범위를 줄이는 방법을 고안한다.</li>
<li>탐색 범위를 줄여도 올바른 결과를 낸다는 강한 믿음을 가진다.</li>
<li>믿음을 가지고 구현해서 문제를 통과한다.</li>
</ol>
<h1 id="코딩테스트에서의-추천-전략">코딩테스트에서의 추천 전략</h1>
<h2 id="case-1">Case 1</h2>
<p>거의 똑같은 문제를 풀어봤거나 간단한 문제여서 나의 그리디 풀이를 100% 확신한다.
-&gt; 짜서 제출해보고, 틀리면 빠르게 손절 (멘탈이 흔들려도 다음 문제로 Go)</p>
<h2 id="case-2">Case 2</h2>
<p>100% 확신은 없지만 맞는 것 같은 그리디 풀이를 찾았다.
-&gt; 일단은 넘어가고 다른 문제를 풀 게 없거나 종료가 20-40분 남은 시점에 코딩 시작</p>
<p>💡 사실 그리디 문제가 아닌데 그리디라고 착각하는 경우가 더 많으니 안되면 넘어가는 전략!</p>
<h1 id="연습-문제">연습 문제</h1>
<ol>
<li>11047번: 동전 0 <a href="https://www.acmicpc.net/problem/11047">(링크)</a></li>
</ol>
<hr>
<ol start="2">
<li>1931번: 회의실배정 <a href="https://www.acmicpc.net/problem/1931">(링크)</a></li>
</ol>
<ul>
<li>명제: 현재 시간이 t라고 할 때, 시작 시간이 t 이상인 모든 회의 중에서 가장 먼저 끝나는 회의를 택하는 것이 최적해이다.</li>
<li>_귀류법_으로 증명<ul>
<li>현재 시간이 t라고 할 때, 시작 시간이 t 이상인 모든 회의 중에서 가장 먼저 끝나는 회의(A)가 아닌 다른 회의(B)를 택했을 때 더 많은 회의를 배정할 수 있다고 가정<ul>
<li>회의 A를 택했을 때 적어도 회의 B를 택했을 때만큼의 회의는 진행할 수 있다는 게 보장</li>
<li>가정이 모순</li>
</ul>
</li>
</ul>
</li>
</ul>
<blockquote>
<p>귀류법이란?
어떤 명제가 참임을 증명하려 할 때 그 명제의 결론을 부정함으로써 가정(假定) 또는 공리(公理) 등이 모순됨을 보여 간접적으로 그 결론이 성립한다는 것을 증명하는 방법</p>
</blockquote>
<hr>
<ol start="3">
<li>2217번: 로프 <a href="https://www.acmicpc.net/problem/2217">(링크)</a></li>
</ol>
<ul>
<li>명제: 각 로프가 버틸 수 있는 최대 중량의 최솟값 * 로프의 개수가 정답이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 짝지어 제거하기]]></title>
            <link>https://velog.io/@jieun_han/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A7%9D%EC%A7%80%EC%96%B4-%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jieun_han/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A7%9D%EC%A7%80%EC%96%B4-%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 12 Jun 2022 11:42:53 GMT</pubDate>
            <description><![CDATA[<p>💻 C++ 기반</p>
<blockquote>
<p>코딩테스트 연습 - 짝지어 제거하기
<a href="https://programmers.co.kr/learn/courses/30/lessons/12973">https://programmers.co.kr/learn/courses/30/lessons/12973</a></p>
</blockquote>
<p>✔️ 짝을 찾는 거니까 _스택_을 이용해서 짝을 바로 삭제해버리기</p>
<hr>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;stack&gt;

using namespace std;

int solution(string s)
{
    int answer = -1;

    // [실행] 버튼을 누르면 출력 값을 볼 수 있습니다.
    cout &lt;&lt; &quot;Hello Cpp&quot; &lt;&lt; endl;

    stack&lt;char&gt; stack_str;
    for (int i = 0; i &lt; s.size(); i++)
    {
        if (stack_str.empty())
        {
            stack_str.push(s[i]);
        }
        else
        {
            if (stack_str.top() == s[i])
            {
                stack_str.pop();
            }
            else
            {
                stack_str.push(s[i]);
            }
        }
    }

    if (stack_str.empty())
    {
        answer = 1;
    }
    else
    {
        answer = 0;
    }

    return answer;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 프린터]]></title>
            <link>https://velog.io/@jieun_han/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%ED%94%84%EB%A6%B0%ED%84%B0</link>
            <guid>https://velog.io/@jieun_han/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%ED%94%84%EB%A6%B0%ED%84%B0</guid>
            <pubDate>Mon, 06 Jun 2022 10:05:03 GMT</pubDate>
            <description><![CDATA[<p>💻 C++ 기반</p>
<blockquote>
<p>코딩테스트 연습 - 프린터
<a href="https://programmers.co.kr/learn/courses/30/lessons/42587">https://programmers.co.kr/learn/courses/30/lessons/42587</a></p>
</blockquote>
<p>✔️ 인쇄 대기목록은 queue 사용
✔️ 인쇄 대기목록의 가장 높은 중요도 체크하는 방법: 변수 따로 빼서 queue 순회하며 체크</p>
<hr>
<pre><code class="language-cpp">#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;queue&gt;
#include &lt;algorithm&gt;

using namespace std;

int solution(vector&lt;int&gt; priorities, int location) {
    int answer = 0;

    queue&lt;int&gt; waiting;
    for (int i = 0; i &lt; priorities.size(); i++)
    {
        waiting.push(i);
    }

    int cnt = 1;
    while (1)
    {
        int front = waiting.front();
        waiting.pop();

        int sz = waiting.size();
        int max_priority = -1;
        for (int i = 0; i &lt; sz; i++)
        {
            int cur = waiting.front();
            waiting.pop();
            max_priority = max(max_priority, priorities[cur]);
            waiting.push(cur);
        }

        if (priorities[front] &lt; max_priority)
        {
            waiting.push(front);
        }
        else
        {
            if (front == location)
            {
                answer = cnt;
                break;
            }
            cnt++;
        }
    }

    return answer;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring Boot] 회원 관리 예제]]></title>
            <link>https://velog.io/@jieun_han/Spring-Boot-%ED%9A%8C%EC%9B%90-%EA%B4%80%EB%A6%AC-%EC%98%88%EC%A0%9C</link>
            <guid>https://velog.io/@jieun_han/Spring-Boot-%ED%9A%8C%EC%9B%90-%EA%B4%80%EB%A6%AC-%EC%98%88%EC%A0%9C</guid>
            <pubDate>Mon, 30 May 2022 03:02:51 GMT</pubDate>
            <description><![CDATA[<h1 id="0-일반적인-웹-애플리케이션-계층-구조">0. 일반적인 웹 애플리케이션 계층 구조</h1>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/9738c514-95f3-4a8c-a1cb-daed6fbdc96e/image.png" alt=""></p>
<ul>
<li><strong>컨트롤러</strong>: 웹 MVC의 컨트롤러 역할</li>
<li><strong>서비스</strong>: 핵심 비즈니스 로직 구현</li>
<li><strong>리포지토리</strong>: 데이터베이스에 접근, 도메인 객체를 DB에 저장하고 관리</li>
<li><strong>도메인</strong>: 비즈니스 도메인 객체 (e.g. 회원, 주문, 쿠폰 등 주로 데이터베이스에 저장하고 관리됨)</li>
</ul>
<hr>
<h1 id="1-비즈니스-요구사항-정리">1. 비즈니스 요구사항 정리</h1>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/deb2266c-29f0-45f8-bc95-6be821f5a411/image.png" alt=""></p>
<ul>
<li>아직 데이터 저장소가 선정되지 않아, 인터페이스로 구현 클래스를 변경할 수 있도록 설계</li>
</ul>
<hr>
<h1 id="2-도메인-생성">2. 도메인 생성</h1>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/df729921-cedb-43ae-aef2-831d63f18ab0/image.png" alt=""></p>
<ul>
<li>위와 같이 domain 패키지에 Member 클래스 생성</li>
</ul>
<pre><code class="language-java">package hello.hellospring.domain;

public class Member {

    private Long id; // 회원 아이디
    private String name; // 회원 이름

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}</code></pre>
<hr>
<h1 id="3-리포지토리-생성">3. 리포지토리 생성</h1>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/6db5a953-4fb5-417e-b1da-d4e5e5735b80/image.png" alt=""></p>
<ul>
<li>위와 같이 repository 패키지에 MemberRepository 인터페이스와 MemoryMemberRepository 클래스 생성</li>
</ul>
<h2 id="1-인터페이스">1) 인터페이스</h2>
<pre><code class="language-java">package hello.hellospring.repository;

import hello.hellospring.domain.Member;

import java.util.List;
import java.util.Optional;

public interface MemberRepository {
    Member save(Member member); // 회원 정보 저장
    Optional&lt;Member&gt; findById(Long id); // 회원 아이디로 조회
    Optional&lt;Member&gt; findByName(String name); // 회원 이름으로 조회
    List&lt;Member&gt; findAll(); // 회원 정보를 리스트로 반환
}</code></pre>
<ul>
<li>Optional의 경우에는 null 값 처리할 때 유용 <a href="https://mangkyu.tistory.com/70">(참고)</a></li>
</ul>
<h2 id="2-구현-클래스">2) 구현 클래스</h2>
<pre><code class="language-java">package hello.hellospring.repository;

import hello.hellospring.domain.Member;

import java.util.*;

public class MemoryMemberRepository implements MemberRepository {

    // 실무에서는 동시성 문제때문에 ConcurrentHashMap, AtomicLong을 사용하는 경우가 많음
    private static Map&lt;Long, Member&gt; store = new HashMap&lt;&gt;();
    private static long sequence = 0L;

    @Override
    public Member save(Member member) {
        member.setId(++sequence);
        store.put(member.getId(), member);
        return member;
    }

    @Override
    public Optional&lt;Member&gt; findById(Long id) {
        return Optional.ofNullable(store.get(id));
    }

    @Override
    public Optional&lt;Member&gt; findByName(String name) {
        return store.values().stream()
                .filter(member -&gt; member.getName().equals(name))
                .findAny();
    }

    @Override
    public List&lt;Member&gt; findAll() {
        // 실무에서는 loop 돌리기 편하게 리스트를 많이 씀
        return new ArrayList&lt;&gt;(store.values());
    }

    public void clearStore() {
        store.clear();
    }
}</code></pre>
<hr>
<h1 id="4-리포지토리-테스트">4. 리포지토리 테스트</h1>
<ul>
<li>main 메소드나 컨트롤러로 기능을 실행하면 실행하는 데 오래 걸리고, 반복 실행하기 어렵고, 여러 테스트를 한번에 실행하기 어려움</li>
<li>JUnit을 사용하자<blockquote>
<p>간단한 junit 테스트 방법 IntelliJ
<a href="https://log-laboratory.tistory.com/203">https://log-laboratory.tistory.com/203</a></p>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/48d2d4b7-2540-4b9f-8501-3f30ab13eff7/image.png" alt=""></p>
<ul>
<li>위와 같이 test 폴더에 repository 패키지를 만들고, 테스트 클래스 생성</li>
</ul>
<pre><code class="language-java">package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class MemoryMemberRepositoryTest {

    MemoryMemberRepository repository = new MemoryMemberRepository();

    @AfterEach
    public void afterEach() {
        // 각 테스트가 실행되는 순서를 지정할 수 없으므로 순서에 대한 의존성을 없애기 위함
        // 이전 테스트의 결과가 다음 테스트에 영향을 미칠 수 있으므로 데이터 삭제 필요
        repository.clearStore();
    }

    @Test
    public void save() {
        Member member = new Member();
        member.setName(&quot;spring&quot;);
        repository.save(member);

        Member result = repository.findById(member.getId()).get();

        assertThat(member).isEqualTo(result);
    }

    @Test
    public void getByName() {
        Member member1 = new Member();
        member1.setName(&quot;spring1&quot;);
        repository.save(member1);

        Member member2 = new Member();
        member2.setName(&quot;spring2&quot;);
        repository.save(member2);

        Member result = repository.findByName(&quot;spring1&quot;).get();

        assertThat(result).isEqualTo(member1);
    }

    @Test
    public void findAll() {
        Member member1 = new Member();
        member1.setName(&quot;spring1&quot;);
        repository.save(member1);

        Member member2 = new Member();
        member2.setName(&quot;spring2&quot;);
        repository.save(member2);

        List&lt;Member&gt; result = repository.findAll();

        assertThat(result.size()).isEqualTo(2);
    }
}</code></pre>
<hr>
<h1 id="5-서비스-개발">5. 서비스 개발</h1>
<ul>
<li>서비스 개발 관련된 코드에서 네이밍은 최대한 &#39;비즈니스 용어&#39;를 사용할 것
<img src="https://velog.velcdn.com/images/jieun_han/post/115108ac-ce8d-4a29-b62b-9ddeccbc4bed/image.png" alt=""></li>
<li>위와 같이 service 패키지에 MemberService 클래스 생성</li>
</ul>
<pre><code class="language-java">package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;

import java.util.List;
import java.util.Optional;

public class MemberService {
    private final MemberRepository memberRepository = new MemoryMemberRepository();

    public Long join(Member member) {
        // 같은 이름이 있는 중복 회원 X
        validateDuplicateMember(member);

        memberRepository.save(member);
        return member.getId();
    }

    private void validateDuplicateMember(Member member) {
        memberRepository.findByName(member.getName())
                .ifPresent(m -&gt; {
                    throw new IllegalStateException(&quot;이미 존재하는 회원입니다.&quot;);
                });
    }

    public List&lt;Member&gt; findMembers() {
        return memberRepository.findAll();
    }

    public Optional&lt;Member&gt; findOne(Long memberId) {
        return memberRepository.findById((memberId));
    }
}
</code></pre>
<ul>
<li>private final과 private static final <a href="https://jwdeveloper.tistory.com/179">참고</a></li>
</ul>
<hr>
<h1 id="6-서비스-테스트">6. 서비스 테스트</h1>
<ul>
<li>서비스 클래스에 커서를 두고 Ctrl + Shift + T를 누르면 테스트 코드 자동 생성
<img src="https://velog.velcdn.com/images/jieun_han/post/6d56eb17-4660-496f-a9ed-9db9f2320ab0/image.png" alt=""></li>
<li>위와 같이 test 폴더에 자동으로 생성됨</li>
<li><em>테스트 코드에서 함수명은 한글로 바꿔도 됨</em></li>
<li>빌드할 때 테스트 코드는 포함되지 않음</li>
<li><strong>테스트 코드는 given, when, then 구조로 작성하면 좋음</strong></li>
</ul>
<pre><code class="language-java">package hello.hellospring.service;

import hello.hellospring.domain.Member;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;

import hello.hellospring.repository.MemoryMemberRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class MemberServiceTest {

    MemberService memberService;
    MemoryMemberRepository memberRepository;

    @BeforeEach
    public void beforeEach() {
        // 테스트를 실행할 때마다 독립적으로 생성
        memberRepository = new MemoryMemberRepository();
        memberService = new MemberService(memberRepository);
    }

    @AfterEach
    public void afterEach() {
        memberRepository.clearStore();
    }

    @Test
    void join() {
        /* given */
        Member member = new Member();
        member.setName(&quot;hello&quot;);

        /* when */
        Long saveId = memberService.join(member);

        /* then */
        Member findMember = memberService.findOne(saveId).get();
        assertThat(member.getName()).isEqualTo(findMember.getName());
    }

    @Test
    public void duplicateException() {
        /* given */
        Member member1 = new Member();
        member1.setName(&quot;spring&quot;);

        Member member2 = new Member();
        member2.setName(&quot;spring&quot;);

        /* when */
        memberService.join(member1);
        IllegalStateException e = assertThrows(IllegalStateException.class, () -&gt; memberService.join(member2));
        // 두 번째 인자를 실행하여 첫 번째 인자의 예외 타입이 나오는지 확인

        /* then */
        assertThat(e.getMessage()).isEqualTo(&quot;이미 존재하는 회원입니다.&quot;);
    }

    @Test
    void findMembers() {
    }

    @Test
    void findOne() {
    }
}</code></pre>
<ul>
<li><p>테스트 코드 작성할 때는 예외처리가 잘 되는지 확인하는 게 더 중요!</p>
</li>
<li><p>MemberService.java 파일을 아래와 같이 수정</p>
<pre><code class="language-java">  private final MemberRepository memberRepository;

  public MemberService(MemberRepository memberRepository) {
      // 외부에서 생성
      this.memberRepository = memberRepository;
  }</code></pre>
</li>
</ul>
<hr>
<p>참고: <a href="https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8">[인프런] 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 (김영한)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 행렬 테두리 회전하기]]></title>
            <link>https://velog.io/@jieun_han/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%ED%96%89%EB%A0%AC-%ED%85%8C%EB%91%90%EB%A6%AC-%ED%9A%8C%EC%A0%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jieun_han/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%ED%96%89%EB%A0%AC-%ED%85%8C%EB%91%90%EB%A6%AC-%ED%9A%8C%EC%A0%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 28 May 2022 13:53:48 GMT</pubDate>
            <description><![CDATA[<p>💻 C++ 기반</p>
<blockquote>
<p>코딩테스트 연습 - 행렬 테두리 회전하기
<a href="https://programmers.co.kr/learn/courses/30/lessons/77485?language=cpp">https://programmers.co.kr/learn/courses/30/lessons/77485?language=cpp</a></p>
</blockquote>
<p>✔️ 시작점의 원소를 미리 저장해두기
✔️ 회전하는 방향의 &#39;반대 방향&#39;으로 탐색하면서 2차원 배열 갱신
✔️ 아이디어 참고용(<a href="https://sungone-develop-study.tistory.com/m/35">링크</a>)</p>
<hr>
<pre><code class="language-cpp">#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;

#define MAX 101

using namespace std;

int board[MAX][MAX];
int dirRow[4] = {0, -1, 0, 1}; // 동북서남
int dirCol[4] = {1, 0, -1, 0};

vector&lt;int&gt; solution(int rows, int columns, vector&lt;vector&lt;int&gt;&gt; queries) {
    vector&lt;int&gt; answer;
    for (int i = 1; i &lt;= rows; i++)
    {
        for (int j = 1; j &lt;= columns; j++)
        {
            board[i][j] = (i - 1) * columns + j;
        }
    }

    for (int i = 0; i &lt; queries.size(); i++)
    {
        int x1 = queries[i][0];
        int y1 = queries[i][1];
        int x2 = queries[i][2];
        int y2 = queries[i][3];

        int sz = (x2 - x1 + y2 - y1) * 2;

        int dir = 2;
        int curRow = x1;
        int curCol = y1;

        vector&lt;int&gt; v;
        int temp = board[curRow][curCol];
        for (int j = 0; j &lt; sz; j++)
        {
            if (curRow == x1 &amp;&amp; curCol == y1 || curRow == x2 &amp;&amp; curCol == y1 || curRow == x2 &amp;&amp; curCol == y2 || curRow == x1 &amp;&amp; curCol == y2)
            {
                dir = (dir + 1) % 4; 
            }

            if (j == sz - 1)
            {
                v.push_back(temp);
                board[curRow][curCol] = temp;
            }
            else
            {
                int nextRow = curRow + dirRow[dir];
                int nextCol = curCol + dirCol[dir];
                v.push_back(board[nextRow][nextCol]);
                board[curRow][curCol] = board[nextRow][nextCol];
                curRow = nextRow;
                curCol = nextCol;
            }
        }
        sort(v.begin(), v.end());
        answer.push_back(v[0]);
    }
    return answer;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring Boot] 스프링 입문]]></title>
            <link>https://velog.io/@jieun_han/Spring-Boot-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8</link>
            <guid>https://velog.io/@jieun_han/Spring-Boot-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8</guid>
            <pubDate>Fri, 27 May 2022 07:25:26 GMT</pubDate>
            <description><![CDATA[<h1 id="0-기본적인-개념들">0. 기본적인 개념들</h1>
<p>1) <a href="https://velog.io/@bky373/Web-%EC%9B%B9-%EC%84%9C%EB%B2%84%EC%99%80-WAS">웹 서버와 WAS의 개념 이해</a>
2) <a href="https://melonicedlatte.com/2021/07/11/174700.html">스프링(Spring), 스프링 부트(Spring Boot)란? 개념 정리</a></p>
<blockquote>
<p>Spring이란? <em>자바 기반의 웹 어플리케이션을 만들 수 있는 프레임워크</em></p>
</blockquote>
<hr>
<h1 id="1-프로젝트-환경설정">1. 프로젝트 환경설정</h1>
<h2 id="1-spring-initializr에서-생성">1) spring initializr에서 생성</h2>
<p><img src="https://velog.velcdn.com/images/jieun_han/post/5f4bb5cf-8d35-4216-b7b5-c0bfb3165845/image.png" alt=""></p>
<ul>
<li>위와 같이 설정해준다.</li>
<li>Dependencies에도 Spring Web과 Thymeleaf를 추가해준다.</li>
<li>다 설정했으면 하단에 GENERATE 버튼을 클릭해 압축 파일을 다운로드한다.</li>
</ul>
<h2 id="2-intellij에서-작업">2) IntelliJ에서 작업</h2>
<ul>
<li>src/main/java/HelloSpringApplication.java 실행 후, localhost:8080에 들어가면 explicit mapping이 안 되어 있다고 뜰 것임</li>
</ul>
<h3 id="①-정적인-페이지-생성">① 정적인 페이지 생성</h3>
<ul>
<li>아래와 같이 index.html 파일 생성
<img src="https://velog.velcdn.com/images/jieun_han/post/ec1d4086-0f63-41bc-bfce-0fe0764f1f0a/image.png" alt="">
코드는 아래 참고<pre><code class="language-html">&lt;!DOCTYPE HTML&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Hello&lt;/title&gt;
  &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt;
&lt;/head&gt;
&lt;body&gt;
Hello
&lt;a href=&quot;/hello&quot;&gt;hello&lt;/a&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
</li>
</ul>
<h3 id="②-컨트롤러-생성">② 컨트롤러 생성</h3>
<ul>
<li>아래와 같이 HelloController.java 파일 생성
<img src="https://velog.velcdn.com/images/jieun_han/post/2ab36d02-0c35-40de-bc1b-e9de1afcf444/image.png" alt=""></li>
<li>코드는 아래 참고 (HelloSpringApplication.java)<pre><code class="language-java">package hello.hellospring.controller;
</code></pre>
</li>
</ul>
<p>import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;</p>
<p>@Controller
public class HelloController {
    @GetMapping(&quot;hello&quot;)
    public String hello(Model model) {
        model.addAttribute(&quot;data&quot;, &quot;hello!!&quot;);
        return &quot;hello&quot;; // hello 템플릿 파일을 알아서 찾아서 이동
    }
}</p>
<pre><code>- 아래와 같이 hello.html(템플릿 파일) 생성
![](https://velog.velcdn.com/images/jieun_han/post/860b5b9c-a291-4da1-a942-2ddbc3a4785a/image.png)
- 코드는 아래 참고
```html
&lt;!DOCTYPE HTML&gt;
&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&gt;
&lt;head&gt;
    &lt;title&gt;Hello&lt;/title&gt;
    &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p th:text=&quot;&#39;안녕하세요. &#39; + ${data}&quot;&gt; 안녕하세요. 손님&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><pre><code>- data라는 key값에 hello!!!가 매핑
- &lt;p&gt; 태그 안에 있는 내용은 실제로 매핑이 일어나면 text에 있는 값으로 대체됨
 (&lt;p&gt; 태그 안에 있는 내용은 절대경로로 접근할 때 보이도록 하기 위함)</code></pre><h3 id="③-실행-결과">③ 실행 결과</h3>
<p>localhost:8080
<img src="https://velog.velcdn.com/images/jieun_han/post/b1ac801d-1e08-45af-a293-371dbfd13c6d/image.png" alt=""></p>
<p>localhost:8080/hello
<img src="https://velog.velcdn.com/images/jieun_han/post/1c36bc6d-fca2-4543-982f-ff9ec20a12ef/image.png" alt=""></p>
<h2 id="3-빌드">3) 빌드</h2>
<ul>
<li>Ctrl + F9 또는 빌드 아이콘 클릭</li>
<li>성공적으로 빌드가 되면 아래와 같은 화면 확인 가능
<img src="https://velog.velcdn.com/images/jieun_han/post/9bdd4573-25f0-4476-b5da-5587adc76cb3/image.png" alt=""></li>
</ul>
<hr>
<h1 id="2-스프링-웹-개발-기초">2. 스프링 웹 개발 기초</h1>
<ul>
<li>웹 브라우저로부터 요청이 오면, AWS (e.g. Tomcat)가 Spring 컨테이너를 통해 컨트롤러가 있는지 확인
  -&gt; 없으면 정적인 콘텐츠 반환
  -&gt; 있으면 viewResolver가 Thymeleaf 템플릿 엔진 처리
  -&gt; 만약 @ResponseBody가 있다면 HttpMessageConverter가 처리 (JsonConverter, StringConverter)</li>
</ul>
<h2 id="1-정적-콘텐츠-방식">1) 정적 콘텐츠 방식</h2>
<ul>
<li>서버 필요 X</li>
<li>파일을 그냥 웹 브라우저에 전달</li>
<li>2) - ① 내용 참고</li>
</ul>
<h2 id="2-mvc와-템플릿-엔진">2) MVC와 템플릿 엔진</h2>
<ul>
<li>php와 같은 템플릿 엔진을 통해 HTML을 동적으로 바꿈</li>
<li>서버에서 좀 변경을 한 파일을 웹 브라우저에 전달</li>
<li>2) - ② 내용 참고</li>
<li>만약 파라미터를 추가하게 된다면, 주소창에도 파라미터를 명시해줘야 함
<img src="https://velog.velcdn.com/images/jieun_han/post/218c13ee-60be-430d-9b8f-22ad96a620c3/image.png" alt=""></li>
<li>코드는 아래 참고 (HelloSpringApplication.java)<pre><code class="language-java">package hello.hellospring.controller;
</code></pre>
</li>
</ul>
<p>import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;</p>
<p>@Controller
public class HelloController {
    @GetMapping(&quot;hello-mvc&quot;)
    public String helloMvc(@RequestParam(&quot;name&quot;) String name, Model model) { // 파라미터 명시
        model.addAttribute(&quot;name&quot;, name);
        return &quot;hello-template&quot;;
    }
}</p>
<pre><code>
## 3) API
- json이라는 데이터 포맷으로 client에 데이터 전달
- 안드로이드, React 등 다양한 플랫폼 사이에서 통신할 때 사용
- 코드는 아래 참고 (HelloSpringApplication.java)
```java
package hello.hellospring.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {    
    @GetMapping(&quot;hello-string&quot;)
    @ResponseBody // HTTP 통신의 body 부분에 직접 넣어주겠다는 의미
    public String helloString(@RequestParam(&quot;name&quot;) String name) {
        return &quot;hello &quot; + name;
    }

    @GetMapping(&quot;hello-api&quot;)
    @ResponseBody
    public Hello helloApi(@RequestParam(&quot;name&quot;) String name) {
        Hello hello = new Hello();
        hello.setName(name);
        return hello; // 객체로 (json 형식) 반환됨
    }
    static class Hello {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}</code></pre><p>localhost:8080/hello-api?name=spring
<img src="https://velog.velcdn.com/images/jieun_han/post/e43045db-1646-4433-8960-f34e0f43f094/image.png" alt=""></p>
<hr>
<p>참고: <a href="https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8">[인프런] 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 (김영한)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Androidx] Room]]></title>
            <link>https://velog.io/@jieun_han/Androidx-Room</link>
            <guid>https://velog.io/@jieun_han/Androidx-Room</guid>
            <pubDate>Mon, 23 May 2022 13:29:21 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>📍 <strong>androidx.room</strong> 이란?
안드로이드 앱 개발할 때 SQLite를 활용해 데이터베이스에 엑세스할 수 있도록 만들어주는 API
(A Database Object Mapping library that makes it easy to access database on Android applications)</p>
</blockquote>
<h1 id="1-room-entity-classes">1. Room Entity Classes</h1>
<ul>
<li>데이터베이스의 row에 해당</li>
<li>한 Entity 당 하나의 테이블이 생성됨<pre><code class="language-kotlin">import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
</code></pre>
</li>
</ul>
<p>@Entity
data class History(
    @PrimaryKey val uid: Int?,
    @ColumnInfo(name = &quot;expression&quot;) val expression: String?,
    @ColumnInfo(name = &quot;result&quot;) val result: String?
)</p>
<pre><code>
- data class 대신 public class를 사용해도 되지만, data class를 사용하는 게 좋을 것 같다. [[참고]](https://velog.io/@jonmad/Til.-kotlin-Data-class와-보일러-플레이트)
- PrimaryKey의 경우 자동생성도 가능
```kotlin
@Entity(tableName = &quot;student_data_table&quot;)
data class Student(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = &quot;student_id&quot;)
    var id: Int,
    @ColumnInfo(name = &quot;student_name&quot;)
    var name: String,
    @ColumnInfo(name = &quot;student_email&quot;)
    var email: String
)</code></pre><h1 id="2-dao-interface">2. DAO Interface</h1>
<ul>
<li><p>Data Access Objects</p>
</li>
<li><p>데이터베이스에 접근할 수 있도록 하는 메소드 정의</p>
<pre><code class="language-kotlin">@Dao
interface HistoryDao {
  @Query(&quot;SELECT * FROM history&quot;)
  fun getAll(): List&lt;History&gt;

  // 이렇게 하나씩 insert 할 수 있음
  @Insert
  fun insertHistory(history: History)

  @Query(&quot;DELETE FROM history&quot;)
  fun deleteAll()

  // 이렇게 하나씩 delete 할 수 있음
  @Delete
  fun delete(history: History)

  // 이렇게 조건을 추가할 수 있음
  @Query(&quot;SELECT * FROM history WHERE result LIKE :result&quot;)
  fun findByResult(result: String): List&lt;History&gt;

  @Query(&quot;SELECT * FROM history WHERE result LIKE :result LIMIT 1&quot;)
  fun findOneByResult(result: String): History
}</code></pre>
</li>
</ul>
<h1 id="3-room-database-class">3. Room Database Class</h1>
<ul>
<li>추상 클래스 사용</li>
<li>버전 명시 필요 (migration 코드)</li>
<li>RoomDatabase를 extend</li>
</ul>
<pre><code class="language-kotlin">@Database(entities = [History::class], version = 1)
abstract class AppDatabase: RoomDatabase() {
    abstract fun historyDao(): HistoryDao
}</code></pre>
<hr>
<p>[공식 문서 참고]</p>
<ol>
<li><a href="https://developer.android.com/jetpack/androidx/releases/room?hl=ko">Room 설명</a></li>
<li><a href="https://developer.android.com/reference/androidx/room/package-summary?hl=ko">androidx.room 설명</a></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[2022년 KT 신입사원 채용(SW개발) 코테 후기]]></title>
            <link>https://velog.io/@jieun_han/2022%EB%85%84-KT-%EC%8B%A0%EC%9E%85%EC%82%AC%EC%9B%90-%EC%B1%84%EC%9A%A9SW%EA%B0%9C%EB%B0%9C-%EC%BD%94%ED%85%8C-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@jieun_han/2022%EB%85%84-KT-%EC%8B%A0%EC%9E%85%EC%82%AC%EC%9B%90-%EC%B1%84%EC%9A%A9SW%EA%B0%9C%EB%B0%9C-%EC%BD%94%ED%85%8C-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Mon, 23 May 2022 01:45:14 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>총 120분, 3문제 (알고리즘)</p>
</blockquote>
<ul>
<li>프로그래머스 환경</li>
<li>온라인 감독 O</li>
<li>구글링 불가</li>
<li>10:00~12:00 (접속은 09:30까지)</li>
</ul>
<p><strong>1번 구현, 조합</strong>
    - 접근 방법에 있어서 조합을 선택하지 않을 수도 있는데, 필자는 조합 선택 (next_permutation 이용)
    - 1차원 배열
    - 체감 난이도: 백준 실버 1</p>
<p><strong>2번 구현? DP?</strong>
    - 문제를 이해하느라 시간이 많이 소요 -&gt; 결국 풀지는 X
    - 배열의 길이의 최댓값과 각 원소의 최댓값이 상당히 컸음 -&gt; 아마 구현으로만 풀면 히든 케이스에서 시간 초과가 나오지 않을까 추측 (DP 이용하면 좋을듯)
    - 체감 난이도: 백준 골드 4</p>
<p><strong>3번 구현, 조합</strong>
    - next_permutation 이용
    - 2차원 배열
    - 체감 난이도: 백준 골드 5</p>
<hr>
<p>결론.
오랜만에 코테를 보는거라 약간 걱정됐는데 경험치가 쌓여서 2솔은 그래도 할 수 있었던 것 같다.
난이도는 3월에 본 KT 신입 개발자 공체 코테보다는 쉬웠다.
역시 &#39;구현&#39; 문제가 많이 나오는 것 같다.
DP도 꾸준히 연습할 필요가 있음!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 10822번]]></title>
            <link>https://velog.io/@jieun_han/%EB%B0%B1%EC%A4%80-10822%EB%B2%88</link>
            <guid>https://velog.io/@jieun_han/%EB%B0%B1%EC%A4%80-10822%EB%B2%88</guid>
            <pubDate>Fri, 20 May 2022 09:26:50 GMT</pubDate>
            <description><![CDATA[<p>💻 C++ 기반</p>
<blockquote>
<p>더하기
<a href="https://www.acmicpc.net/problem/10822">https://www.acmicpc.net/problem/10822</a></p>
</blockquote>
<p>✔️ C++에서 문자열을 자를 때 가장 편리한 방법은 sstream 헤더를 사용하는 것</p>
<hr>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;sstream&gt;

using namespace std;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    string str;
    cin &gt;&gt; str;

    vector&lt;string&gt; numbers;
    stringstream ss(str);
    string temp;
    while (getline(ss, temp, &#39;,&#39;))
    {
        numbers.push_back(temp);
    }

    long long result = 0;
    for (int i = 0; i &lt; numbers.size(); i++)
    {
        result += stoll(numbers[i]);
    }

    cout &lt;&lt; result;
    return 0;
}</code></pre>
]]></description>
        </item>
    </channel>
</rss>